![](/img/trans.png)
[英]Why conditional_variable::notify_all may not wake up any thread?
[英]std::conditional_variable::notify_all does not wake up all the threads
我這里有一個簡單的例子:
由於我嘗試學習c ++ 11線程,因此該項目可以稱為學術項目。 這是正在發生的事情的描述。
想象一下一個很大的std::string
,里面有很多匯編源代碼,例如
mov ebx,ecx; \\ r \\ nmov eax,ecx; \\ r \\ n ....
Parse()
函數采用此字符串並通過標記行的開始和結束並將其另存為工作隊列中的string::const_iterators
來查找所有行位置。
之后,有2個工作線程從隊列中彈出此信息,並將子字符串解析為Intstuction類對象。 他們將指令類的結果實例推回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()
發送給等待的線程之后,實際上只有其中一個醒來。 如果我注釋掉Func()
ParseInstruction()
內部對ParseInstruction()
的調用,則兩個線程都將喚醒,否則只有一個線程正在喚醒。 得到一些建議將是很棒的。
假設Func
讀取signaled
並看到它為假。
然后Parse
套signaled
真實,是否notify_all
; 此時Func
不在等待中,因此看不到通知。
然后, Func
等待條件變量並阻塞。
您可以通過將一綹避免這種condMutex
分配給左右signaled
。
這是正確使用條件變量的正常模式-您需要測試和修改要在同一互斥鎖中等待的條件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.