关于"std::conditional_variable".为什么这个代码段会停滞



为什么这个代码段会停滞?

程序打算输出firstsecondthird,而程序在打印了firstsecond之后暂停。

#include <condition_variable>
#include <mutex>
#include <thread>
#include <functional>
#include <iostream>
#include <vector>
class Foo {
public:
Foo() {

}
void first(std::function<void()> printFirst) 
{
{
std::unique_lock<std::mutex> lk(mutex);

cv1.wait(lk, [this](){return 1==state;});
doing = 1;
// printFirst() outputs "first". Do not change or remove this line.
printFirst();

state = 2;
}
cv2.notify_one();
}
void second(std::function<void()> printSecond) 
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=2 )
{
if((1 == state)&&(1 != doing))
{
lk.unlock();
cv1.notify_one();
}
}

cv2.wait(lk, [this](){return 2==state;});
doing = 2;
// printSecond() outputs "second". Do not change or remove this line.
printSecond();

state = 3;
}
cv3.notify_one();
}
void third(std::function<void()> printThird) 
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=3 )
{
if((1 == state)&&(1 != doing))
{
lk.unlock();
cv1.notify_one();
}
else if((2 == state)&&(2 != doing))
{
lk.unlock();
cv2.notify_one();
}
}

cv3.wait(lk, [this](){return 3==state;});
// printThird() outputs "third". Do not change or remove this line.
printThird();

state = 3;
}
}
private:
std::condition_variable cv1;
std::condition_variable cv2;
std::condition_variable cv3;
std::mutex mutex;
int state{1};
int doing{0};
};
int main()
{
Foo foo;
std::vector<std::thread> threads;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.second([]()->void{std::cout <<"second" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.first([]()->void{std::cout <<"first" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.third([]()->void{std::cout <<"third" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::seconds(2));
for(auto itr=threads.begin(); itr!=threads.end(); itr++)
{
itr->join();
}
}

引自@Igor Tandetnik的评论。

根据文件,

模板无效等待(unique_lock&lck,谓词pred(;

lck

其互斥对象当前被锁定的unique_lock对象这个线程。等待此成员函数的所有并发调用对象应使用相同的底层互斥对象(由lck.mutex(((.

因此,cv2.wait(lk, ...)要求lk实际持有mutex

如果删除lk.unlock();,则此代码片段可以按预期工作。

#include <condition_variable>
#include <mutex>
#include <thread>
#include <functional>
#include <iostream>
#include <vector>
class Foo {
public:
Foo() {

}
void first(std::function<void()> printFirst) 
{
{
std::unique_lock<std::mutex> lk(mutex);

cv1.wait(lk, [this](){return 1==state;});
doing = 1;
// printFirst() outputs "first". Do not change or remove this line.
printFirst();

state = 2;
}
cv2.notify_one();
}
void second(std::function<void()> printSecond) 
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=2 )
{
if((1 == state)&&(1 != doing))
{
//lk.unlock();  //removed
cv1.notify_one();
}
}

cv2.wait(lk, [this](){return 2==state;});
doing = 2;
// printSecond() outputs "second". Do not change or remove this line.
printSecond();

state = 3;
}
cv3.notify_one();
}
void third(std::function<void()> printThird) 
{
{
std::unique_lock<std::mutex> lk(mutex);
if(state !=3 )
{
if((1 == state)&&(1 != doing))
{
//lk.unlock();  //removed
cv1.notify_one();
}
else if((2 == state)&&(2 != doing))
{
//lk.unlock();  //removed
cv2.notify_one();
}
}

cv3.wait(lk, [this](){return 3==state;});
// printThird() outputs "third". Do not change or remove this line.
printThird();

state = 3;
}
}
private:
std::condition_variable cv1;
std::condition_variable cv2;
std::condition_variable cv3;
std::mutex mutex;
int state{1};
int doing{0};
};
int main()
{
Foo foo;
std::vector<std::thread> threads;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.second([]()->void{std::cout <<"second" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.first([]()->void{std::cout <<"first" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.third([]()->void{std::cout <<"third" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::seconds(2));
for(auto itr=threads.begin(); itr!=threads.end(); itr++)
{
itr->join();
}
}

代码片段可以改进如下:

#include <condition_variable>
#include <mutex>
#include <thread>
#include <functional>
#include <iostream>
#include <vector>

// @lc code=start
class Foo {
public:
Foo() {

}
void first(std::function<void()> printFirst) 
{
{
std::unique_lock<std::mutex> lk(mutex);
// printFirst() outputs "first". Do not change or remove this line.
printFirst();

state = 2;
}
cv2.notify_one();
}
void second(std::function<void()> printSecond) 
{
{
std::unique_lock<std::mutex> lk(mutex);

cv2.wait(lk, [this](){return 2==state;});
// printSecond() outputs "second". Do not change or remove this line.
printSecond();

state = 3;
}
cv3.notify_one();
}
void third(std::function<void()> printThird) 
{
{
std::unique_lock<std::mutex> lk(mutex);

cv3.wait(lk, [this](){return 3==state;});
// printThird() outputs "third". Do not change or remove this line.
printThird();

state = 3;
}
}
private:
std::condition_variable cv2;
std::condition_variable cv3;
std::mutex mutex;
int state{1};
};
// @lc code=end
int main()
{
Foo foo;
std::vector<std::thread> threads;
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.second([]()->void{std::cout <<"second" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.first([]()->void{std::cout <<"first" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
threads.push_back(std::thread([&](){foo.third([]()->void{std::cout <<"third" <<std::endl;});}));
std::this_thread::sleep_for(std::chrono::seconds(2));
for(auto itr=threads.begin(); itr!=threads.end(); itr++)
{
itr->join();
}
}

最新更新