【发布时间】:2017-10-26 21:07:03
【问题描述】:
我有两个线程。两者都被初始化,但第一个线程首先运行,而第二个线程等待第一个线程 (call_once(flagEven1, [&](){cond2.wait(lock, [&](){return zeroEvenOddFlag == 1; }); });)。在满足某个条件后,第一个线程唤醒第二个线程并进入睡眠状态。
zeroEvenOddFlag = 0;
cond1.notify_all();
cond2.wait(lock, [&](){return zeroEvenOddFlag == 1; });
此过程交替进行,直到任务完成。现在线程刚刚被锁定,我不知道发生了什么。线程应该一起处理输入字符串并产生两个零和非零数字字符串。我通过添加线程之间共享的整数 (zeroEvenOddFlag) 来纠正虚假唤醒。
#include <string>
#include <thread>
#include <future>
#include <cstdio>
#include <iostream>
#include <queue>
#include <condition_variable>
using namespace std;
mutex mu;
condition_variable cond1;
condition_variable cond2;
once_flag flagZero;
once_flag flagEven;
once_flag flagEven1;
int zeroEvenOddFlag = 0;
string printerFunc(queue<char>& input, int zeroEvenOdd, once_flag& flag){
string output = "";
function<void(string&)> f;
unique_lock<mutex> lock(mu);
call_once(flag, [&](){
if (zeroEvenOdd == 1){
f = [&](string& output){
int i = input.front() - '0';
if (i == 0){
output += to_string(i);
input.pop();
}
else {
zeroEvenOddFlag = 1;
cond2.notify_all();
cond1.wait(lock, [&](){return zeroEvenOddFlag == 0; });
}
};
}
else if (zeroEvenOdd == 2){
call_once(flagEven1, [&](){cond2.wait(lock, [&](){return zeroEvenOddFlag == 1; }); });
f = [&](string& output){
int i = input.front() - '0';
if (i != 0){
output += to_string(i);
input.pop();
}
else {
zeroEvenOddFlag = 0;
cond1.notify_all();
cond2.wait(lock, [&](){return zeroEvenOddFlag == 1; });
}
};
}
});
while(input.size()!=0){
f(output);
}
return output;
}
int _tmain(int argc, _TCHAR* argv[])
{
string input = "0102030";
queue<char> inputQueue;
for(char c : input){
inputQueue.push(c);
}
auto zeros = async(launch::async, printerFunc, ref(inputQueue), 1, ref(flagZero));
auto evens = async(launch::async, printerFunc, ref(inputQueue), 2, ref(flagEven));
string zerosString = zeros.get();
string evensString = evens.get();
cout << "these are the zeros " << zerosString << endl;
cout << "these are the evens " << evensString << endl;
this_thread::sleep_for(chrono::seconds(10));
return 0;
}
【问题讨论】:
-
你肯定需要一本关于使用 C++11 进行多线程的好书......你似乎在滥用
std::call_once;您也没有考虑到std::condition_variable::wait的虚假唤醒,以及许多其他问题.. -
我如何滥用 call_once?我想设置一次函数,这就是为什么我有 call_once(flag, [&]()。我想设置一次函数是有原因的,这对手头的问题无关紧要。另一个 call_once 是为了防止第二个线程从甚至开始直到第一个线程允许它。至于condition_variable::wait,我只有一个唤醒线程二的条件,那就是线程一唤醒它。我该如何处理有虚假唤醒 condition_variable::wait 当所有重要的是线程交替时?
-
如果
call_once对手头的问题无关紧要,那为什么不简化代码呢? -
我使用 call_once 的原因无关紧要。我仍然需要使用 call_once。
-
@WhiZTiM,我尝试添加一个子句来防止虚假唤醒。不过,我不明白我是如何不当使用
call_once的。
标签: c++ multithreading