Ant*_*nja 0 c++ multithreading condition-variable thread-synchronization c++11
我在这里有一个简单的例子:
自从我尝试学习c ++ 11线程以来,该项目可称为学术性的.这是对正在发生的事情的描述.
想象一下,如果std::string有大量的汇编源代码,那就非常大
mov ebx,ecx;\r \nmov eax,ecx;\r \n ......
Parse()function接受此字符串并通过标记行的开头和结尾并将其保存string::const_iterators在作业队列中来查找所有行位置.
之后,2个工作线程从队列中弹出此信息,并将子字符串解析为Intstuction类对象.他们将结果的Instruction类实例推送到std::vector<Instruction> result
这是一个结构声明,用于保存要解析的子字符串的行号和迭代器
struct JobItem {
int lineNumber;
string::const_iterator itStart;
string::const_iterator itEnd;
};
Run Code Online (Sandbox Code Playgroud)
那是一个小记录器......
void ThreadLog(const char* log) {
writeMutex.lock();
cout << "Thr:" << this_thread::get_id() << " " << log << endl;
writeMutex.unlock();
}
Run Code Online (Sandbox Code Playgroud)
这是共享数据:
queue<JobItem> que;
vector<Instruction> result;
Run Code Online (Sandbox Code Playgroud)
以下是同步的所有原语
condition_variable condVar;
mutex condMutex;
bool signaled = false;
mutex writeMutex;
bool done=false;
mutex resultMutex;
mutex queMutex;
Run Code Online (Sandbox Code Playgroud)
每线程功能
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();
}
Run Code Online (Sandbox Code Playgroud)
管理线程的管理器功能......
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;
}
Run Code Online (Sandbox Code Playgroud)
问题出现在Func()功能上.如您所见,我正在使用它内部的一些日志记录.日志说:
Output:
Thr:9928 Waiting...
Thr:8532 Waiting...
Thr:8532 Started
Run Code Online (Sandbox Code Playgroud)
这意味着在主线程发送notify_all()到等待线程之后,其中只有一个实际醒来了.如果我注释掉ParseInstruction()内部的调用,Func()则两个线程都会唤醒,否则只有一个线程会这样做.得到一些建议会很棒.
假设Func读取signaled并看到它是假的.
然后Parse设置为signaledtrue并执行notify_all; 此时Func不等待,所以看不到通知.
Func 然后等待条件变量和块.
你可以通过锁定condMutex任务来避免这种情况signaled.
这是正确使用条件变量的正常模式 - 您需要在同一个互斥锁中测试和修改要等待的条件.