У меня есть простой пример здесь:станд :: conditional_variable :: notify_all не просыпаются все темы
Проект можно назвать академическим, так как я пытаюсь научиться C++ 11 потоков. Описание того, что происходит.
Представьте себе очень большой std::string
с много сборки исходного кода внутри как
MOV EBX, ECX; \ г \ nmov EAX, ECX; \ г \ п ....
Parse()
функция принимает эту строку и находит все позиции линии, отмечая начало и конец строки и сохраняя их как string::const_iterators
в очереди заданий.
После этого 2 рабочих потока выкладывают эту информацию из очереди и анализируют подстроку в объект класса Intstuction. Они push_back получившегося экземпляра класса Инструкции в std::vector<Instruction> result
Вот это структура декларация держать номер строки и итераторы для подстроки разобрать
struct JobItem {
int lineNumber;
string::const_iterator itStart;
string::const_iterator itEnd;
};
Это маленький регистратор ...
void ThreadLog(const char* log) {
writeMutex.lock();
cout << "Thr:" << this_thread::get_id() << " " << log << endl;
writeMutex.unlock();
}
Это общие данные:
queue<JobItem> que;
vector<Instruction> result;
Здесь все примитивы для синхронизации
condition_variable condVar;
mutex condMutex;
bool signaled = false;
mutex writeMutex;
bool done=false;
mutex resultMutex;
mutex queMutex;
Межпоточной функция
void Func() {
unique_lock<mutex> condLock(condMutex);
ThreadLog("Waiting...");
while (!signaled) {
condVar.wait(condLock);
}
ThreadLog("Started");
while (!done) {
JobItem item;
queMutex.lock();
if (!que.empty()) {
item = que.front(); que.pop();
queMutex.unlock();
}
else {
queMutex.unlock();
break;
}
//if i comment the line below both threads wake up
auto instr = ParseInstruction(item.itStart, item.itEnd);
resultMutex.lock();
result.push_back(Instruction());
resultMutex.unlock();
}
Функция менеджера, который управляет темой ...
vector<Instruction> Parser::Parse(const string& instructionStream){
thread thread1(Func);
thread thread2(Func);
auto it0 = instructionStream.cbegin();
auto it1 = it0;
int currentIndex = instructionStream.find("\r\n");
int oldIndex = 0;
this_thread::sleep_for(chrono::milliseconds(1000)); //experimental
int x = 0;
while (currentIndex != string::npos){
auto it0 = instructionStream.cbegin() + oldIndex;
auto it1 = instructionStream.cbegin() + currentIndex;
queMutex.lock();
que.push({ x,it0,it1 });
queMutex.unlock();
if (x == 20) {//fill the buffer a little bit before signal
signaled = true;
condVar.notify_all();
}
oldIndex = currentIndex + 2;
currentIndex = instructionStream.find("\r\n", oldIndex);
++x;
}
thread1.join();
thread2.join();
done = true;
return result;
}
Проблемы возникает в функции Func()
, Как вы можете видеть, я использую некоторые записи в нем. И журналы говорят:
Output:
Thr:9928 Waiting...
Thr:8532 Waiting...
Thr:8532 Started
Это означает, что после того, как основной поток отправило notify_all()
к ожидающим потокам, только один из них на самом деле проснулся. Если я прокомментирую звонок ParseInstruction()
внутри Func()
, тогда оба потока проснутся, иначе только один сделает это. Было бы здорово получить совет.
Можете ли вы предоставить [** минимальный ** полный и проверяемый пример] (http://www.stackoverflow.com/help/mcve)? – Barry
Назначение 'signaled' не защищено' condMutex', поэтому 'Func', возможно, никогда его не увидит. –
Не могли бы вы быть более конкретными? – Antiusninja