如何降低生产者获得锁的可能性,而消费者在使用std::condition_variable时无法获得锁?

How to decrese the possibility of the producer acquiring the lock whereas the consumer could not get the lock when using std::condition_variable?

本文关键字:condition std variable 生产者 何降低 可能性 消费者      更新时间:2023-10-16

如何降低生产者(即下面代码片段代码中的主线程(获取锁而消费者(即等待线程(无法获得锁的可能性?如果你能告诉我一种避免它的方法,那就更好了。我认为使用std::thread::sleep_forstd::thread::yield不是一个好主意.而且我做了一些测试,发现使用std::thread::yield时没有效果。

我已经考虑了很长时间,如果能在这个问题上得到一些帮助,我将不胜感激。

如果运行代码片段,可能会看到以下输出:

Waiting... 
test 
Notifying falsely... 
Notifying true change... 
Notifying true change... 
Notifying true change... 
Notifying true change... 
Notifying true change... 
Notifying true change...
(**many many such output**)
Notifying true change... 
test 
...finished waiting. i == 1

以下是相关的代码片段(检查 https://godbolt.org/z/9dwDJN,引用自 en.cppreference.com/w/cpp/thread/condition_variable/notify_one(:

#include <iostream>
#include <condition_variable>
#include <thread>
#include <chrono>
std::condition_variable cv;
std::mutex cv_m;
int i = 0;
bool done = false;
void waits()
{
std::unique_lock<std::mutex> lk(cv_m);
std::cout << "Waiting... n";
cv.wait(lk, []{std::cout<<"test"<<std::endl; return i == 1;});
std::cout << "...finished waiting. i == 1n";
done = true;
}
void signals()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Notifying falsely...n";
cv.notify_one(); // waiting thread is notified with i == 0. 
// cv.wait wakes up, checks i, and goes back to waiting 
std::unique_lock<std::mutex> lk(cv_m);
i = 1;
while (!done)
{
std::cout << "Notifying true change...n";
lk.unlock();
cv.notify_one(); // waiting thread is notified with i == 1, cv.wait returns 
//std::this_thread::sleep_for(std::chrono::seconds(1));   // I don't think it is good method.
//std::this_thread::yield();  //Maybe, this does not work.
lk.lock();
}
}
int main()
{
std::thread t1(waits), t2(signals);
t1.join();
t2.join();
}

如果你把它作为一个原子变量,你可以完全等待done没有锁。在这种情况下,这对我来说甚至比使用互斥锁更有意义。但是,这并没有改变忙于等待的整个概念,即循环旋转直到设置done

或者,您可以等待设置done而不阻塞 CPU 内核。只需使用相同的条件变量概念。您甚至可以使用用于同步i的相同条件变量。此方法的演示如下:https://en.cppreference.com/w/cpp/thread/condition_variable。

问题是这两种解决方案中哪一种"更好"。我可能更喜欢第一个基于旋转的解决方案,因为可以预期,等待时间会非常短(如果系统没有超额订阅等(。

为什么你认为使用睡眠是一个不好的想法? 使用std::this_thread::sleep_for(std::chrono::milliseconds(100((是非常标准的;在 while(true( 线程中,它也会解决您的问题。