假设我们有一个单生产者线程单消费者线程无锁队列,并且生产者可能会长时间没有产生任何数据.当队列中没有任何东西时,让消费者线程休眠是有益的(为了节省电力并为其他进程/线程释放CPU).如果队列不是无锁的,解决这个问题的直接方法是让生成线程锁定互斥锁,执行其工作,发出条件变量信号并解锁,并为读取线程锁定互斥锁,等待条件变量,做它的阅读,然后解锁.但是,如果我们使用无锁队列,使用互斥锁的方式完全相同,就会消除我们首先使用无锁队列所获得的性能.
天真的解决方案是让每个插入队列后的生产者锁定互斥锁,发出条件变量信号,然后解锁互斥锁,保持实际工作(插入队列)完全在锁外,并让消费者做同样,锁定互斥锁,等待条件变量,解锁它,将所有内容从队列中拉出,然后重复,保持队列的读取在锁外.这里有一个竞争条件:在读取器拉出队列并进入睡眠状态之间,生产者可能已经将一个项目插入队列中.现在读者将进入睡眠状态,并且可以无限期地保持这种状态,直到生产者插入另一个项目并再次发出状态变量信号.这意味着您偶尔会遇到特定的项目,这些项目似乎需要很长时间才能通过队列.如果您的队列始终处于活动状态,这可能不是问题,但如果它始终处于活动状态,您可能完全忘记了条件变量.
AFAICT解决方案是让生产者的行为与使用常规需求锁定队列的行为相同.它应该锁定互斥锁,插入无锁队列,发出条件变量信号,解锁.但是,消费者的行为应该不同.当它唤醒时,它应立即解锁互斥锁,而不是等到它读取队列.然后它应尽可能多地拉出队列并处理它.最后,只有当消费者想要进入睡眠状态时,它是否应该锁定互斥锁,检查是否有任何数据,然后如果解锁并处理它,或者如果没有,则等待条件变量.这样,互斥锁的争用频率低于锁定队列的频率,但是没有数据仍然留在队列中的睡眠风险.
这是最好的方法吗?还有替代品吗?
注意:通过'最快',我的意思是'最快没有专门核心来反复检查队列',但这不适合标题; p
一种替代方案:使用天真的解决方案,但让消费者等待条件变量,其超时对应于您愿意容忍通过队列的项目的最大延迟.如果所需的超时时间相当短,则可能低于操作系统的最短等待时间,或者仍然消耗过多的CPU.
我们可以使用新的条件变量原语或windows事件来同步WinNT v6.x或更高版本中的线程.考虑以下两种方法,我们希望工作者在main中设置"go"的同时运行,否则它们都应该阻塞.
/*language C code*/
/*Windows Condition Variable*/
int go=0;
CONDITION_VARIABLE cv;
SRWLOCK lock;
void workers()
{
AcquireSRWLockShared(&lock);
if(go==0)
{
SleepConditionVariableSRW(&cv, &lock, INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED);
}
ReleaseSRWLockShared(&lock);
/*
Workers continue...
*/
}
void main()
{
int i;
InitializeConditionVariable(&cv);
InitializeSRWLock(&lock);
for(i=0;i<10;i++)
{
CreateThread(0, 0, workers, 0, 0, 0);
}
AcquireSRWLockExclusive(&lock);
go=1;
ReleaseSRWLockExclusive(&lock);
WakeAllConditionVariable(&cv);
}
Run Code Online (Sandbox Code Playgroud)
要么
/*language C code*/
/*Windows Event*/
HANDLE go;
void workers()
{
WaitForSingleObject(go, INFINITE);
/*
Workers continue...
*/
}
void main()
{
int i;
go=CreateEvent(0,1,0,0); /*No security descriptor, Manual …Run Code Online (Sandbox Code Playgroud) c windows multithreading condition-variable readerwriterlockslim
我正在尝试用C++编写一个用Linux编写的程序的windows版本.对于程序是线程安全的,我用pthread_cond_t和pthread_cond_wait在Linux版本.这些函数使用互斥锁来帮助确保等待的线程实际上正在等待.
我发现CONDITION_VARIABLE在Windows 中可能会有这个技巧,但我无法弄清楚为什么它不会编译.我得到错误"错误:'CONDITION_VARIABLE'没有命名类型",即使包括所有相关的标题,据我所知.我试着在http://msdn.microsoft.com/en-us/library/ms686903%28v=VS.85%29.aspx上复制粘贴代码,它也不会编译.我正在使用GCC.
关于如何编译这个的任何想法?或任何其他方法,不涉及condition_variables?
我无法使代码在一个简单的VS2012控制台应用程序中可靠地运行,该应用程序由使用C++ 11条件变量的生产者和使用者组成.我的目标是生成一个小的可靠程序(用作更复杂程序的基础),它使用3参数wait_for方法或者我在这些网站上收集的代码中的wait_until方法:
condition_variable: wait_for, wait_until
我想使用3参数wait_for和下面的谓词,除非它需要使用类成员变量对我以后最有用.我只在运行一分钟后收到"访问冲突写入位置0x_ _ "或"无效参数已传递给服务或功能"作为错误.
steady_clock和2参数wait_until是否足以替换3参数wait_for?我也试过这个没有成功.
有人可以展示如何使用下面的代码无限期地运行,没有错误或奇怪的行为,从夏令时或互联网时间同步的挂钟时间的变化?
链接到可靠的示例代码可能同样有用.
// ConditionVariable.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <condition_variable>
#include <mutex>
#include <thread>
#include <iostream>
#include <queue>
#include <chrono>
#include <atomic>
#define TEST1
std::atomic<int>
//int
qcount = 0; //= ATOMIC_VAR_INIT(0);
int _tmain(int argc, _TCHAR* argv[])
{
std::queue<int> produced_nums;
std::mutex m;
std::condition_variable cond_var;
bool notified = false;
unsigned int count = 0;
std::thread producer([&]() {
int i = 0;
while (1) …Run Code Online (Sandbox Code Playgroud) c++ multithreading condition-variable c++11 visual-studio-2012
如您所知,应该在循环中调用条件变量以避免虚假唤醒.像这样:
while (not condition)
condvar.wait();
Run Code Online (Sandbox Code Playgroud)
如果另一个线程想要唤醒等待线程,则必须将condition标志设置为true.例如:
condition = true;
condvar.notify_one();
Run Code Online (Sandbox Code Playgroud)
我想知道,这种情况是否有可能阻止条件变量:
1)等待线程检查条件标志,发现它等于FALSE,因此,它将进入condvar.wait()例程.
2)但就在此之前(但是在条件标志检查之后)等待线程被内核抢占(例如,因为时隙到期).
3)此时,另一个线程想要通知等待线程有关条件.它将条件标志设置为TRUE并调用condvar.notify_one();
4)当内核调度程序再次运行第一个线程时,它进入condvar.wait()例行程序,但通知已经丢失.
因此,等待线程无法退出condvar.wait(),尽管条件标志设置为TRUE,因为不再有唤醒通知.
可能吗?
我正在尝试使用C++ 11 std :: condition_variable,但是当我尝试从第二个线程锁定与之关联的unique_lock时,我得到一个异常"资源死锁避免".创建它的线程可以锁定和解锁它,但不能锁定和解锁它,即使我非常确定在第二个线程试图锁定它时不应该锁定unique_lock.
FWIW我在Linux中使用gcc 4.8.1和-std = gnu ++ 11.
我已经在condition_variable,unique_lock和mutex周围写了一个包装类,所以我的代码中没有其他东西可以直接访问它们.注意使用std :: defer_lock,我已经陷入了陷阱:-).
class Cond {
private:
std::condition_variable cCond;
std::mutex cMutex;
std::unique_lock<std::mutex> cULock;
public:
Cond() : cULock(cMutex, std::defer_lock)
{}
void wait()
{
std::ostringstream id;
id << std::this_thread::get_id();
H_LOG_D("Cond %p waiting in thread %s", this, id.str().c_str());
cCond.wait(cULock);
H_LOG_D("Cond %p woke up in thread %s", this, id.str().c_str());
}
// Returns false on timeout
bool waitTimeout(unsigned int ms)
{
std::ostringstream id;
id << std::this_thread::get_id();
H_LOG_D("Cond %p waiting (timed) in thread %s", this, …Run Code Online (Sandbox Code Playgroud) 各种平台都允许虚假wakup.为了解决这个问题,我们在下面写出循环机制:
while(ContinueWaiting())
cv.wait(lock); // cv is a `std::conditional_variable` object
Run Code Online (Sandbox Code Playgroud)
同样的事情是可以理解的conditional_variable::wait_until().
但请看下面的例子:
const auto duration = Returns_10_seconds();
while(!Predicate())
cv.wait_for(lock, duration);
Run Code Online (Sandbox Code Playgroud)
想象一下,虚假的唤醒发生在1秒钟.超时尚未达成.
它会再等10秒吗?这将导致无限循环,我相信不应该发生.从源代码,内部wait_for()调用wait_until().
我想了解,如何wait_for()处理虚假的唤醒?
在std :: condition_variable的文档中,使用谓词函数作为参数的wait()重载。该函数将一直等到谓词函数为true的第一次wake_up。
在文档中
据说这相当于:
while (!pred()) {
wait(lock);
}
Run Code Online (Sandbox Code Playgroud)
但是也:
在等待特定条件变为真时,可以使用此重载来忽略虚假唤醒。请注意,在进入此方法之前,必须先获取锁,在wait(lock)退出后也必须重新获取它,即锁可以用作pred()访问的保护。
我不确定这些是严格等同的(在这种情况下,我更喜欢普通的while循环,而在我的情况下,这种循环比带有lambda的重载更易于阅读),或者重载(可能取决于实现)更有效?
为了避免测试条件为假时唤醒,实现是否可以在唤醒等待线程之前评估通知线程中的谓词?这里需要c ++线程大师...
谢谢
这是Can C++ 11的后续条件condition_variables用于同步进程?.
std :: condition_variable对象可以用作计数信号量吗?
Methinks不是因为对象似乎绑定到std :: mutex,这意味着它只能用作二进制信号量.我在网上看过,包括这里,这里和这里,但是找不到使用这些对象作为计数信号量的参考或示例.
在C++ Concurrency in Action的第6章中,它实现了一个线程安全的队列.这是完整的代码.但我发现使用条件变量可能有问题.
std::unique_lock<std::mutex> wait_for_data()
{
std::unique_lock<std::mutex> head_lock(head_mutex);
data_cond.wait(head_lock, [&] {return head.get() != queue::get_tail(); });
return std::move(head_lock);
}
void push(T new_value)
{
std::shared_ptr<T> new_data(
std::make_shared<T>(std::move(new_value)));
std::unique_ptr<node> p(new node);
{
std::lock_guard<std::mutex> tail_lock(tail_mutex);
tail->data = new_data;
node *const new_tail = p.get();
tail->next = std::move(p);
tail = new_tail;
}
data_cond.notify_one();
}
Run Code Online (Sandbox Code Playgroud)
消耗部件锁定head_mutex,但生产部件锁定tail_mutex,可能导致消费者错过通知.我好吗?