C++ boost::wait和boost::condition是否必须共享同一个互斥对象 boost::条件变量cond; 互斥互斥; //螺纹#1 对于(;;) { D*D=nullptr; 而(cb.pop(d))//cb是一个循环缓冲区,manage在内部是自己的互斥锁/锁 { //…用d做点什么 } boost::唯一的锁(互斥锁); 条件等待(互斥); } //螺纹#2 而(1) { getchar(); 对于(int i=0;i
我想知道我的数据容器是否有自己的锁以避免数据竞争,另一方面boost::wait是否可以使用boost文档指定的锁/互斥机制 否则,thread1就是consummer,如果我只有一个线程“consumme”,那么wait所需的锁似乎有点多余,不是吗C++ boost::wait和boost::condition是否必须共享同一个互斥对象 boost::条件变量cond; 互斥互斥; //螺纹#1 对于(;;) { D*D=nullptr; 而(cb.pop(d))//cb是一个循环缓冲区,manage在内部是自己的互斥锁/锁 { //…用d做点什么 } boost::唯一的锁(互斥锁); 条件等待(互斥); } //螺纹#2 而(1) { getchar(); 对于(int i=0;i,c++,multithreading,boost,c++11,C++,Multithreading,Boost,C++11,我想知道我的数据容器是否有自己的锁以避免数据竞争,另一方面boost::wait是否可以使用boost文档指定的锁/互斥机制 否则,thread1就是consummer,如果我只有一个线程“consumme”,那么wait所需的锁似乎有点多余,不是吗 编辑:我不关心缺少的更新。当我收到更新时,我用收到的数据更新对象。我只需要更新,不需要所有udpate如果您的环形缓冲区的push和pop功能是线程安全的,那么您不需要额外的同步 如果有多个读卡器,则可以使用读卡器/写卡器锁来启用多个线程同时读取。
编辑:我不关心缺少的更新。当我收到更新时,我用收到的数据更新对象。我只需要更新,不需要所有udpate如果您的环形缓冲区的
push
和pop
功能是线程安全的,那么您不需要额外的同步
如果有多个读卡器,则可以使用读卡器/写卡器锁来启用多个线程同时读取。通常,应使用条件变量来表示线程之间共享的条件,以便以线程安全的方式访问该条件。但是,在等待时需要解锁互斥锁,以便其他线程可以更改条件。有关队列的示例,请参见
在您的情况下,您已经有一个线程安全容器。将Condition变量放在容器中并让它使用其互斥锁不是更好吗?condvar必须使用保护数据的互斥锁(好的,不完全是,下面更精确),否则您将错过更新:
boost::condition_variable cond;
boost::mutex mutex;
//thread #1
for(;;)
{
D * d = nullptr;
while( cb.pop(d) ) //cb is a circular buffer and manage is own mutex/lock internally
{
//...do something with d
}
boost::unique_lock<boost::_mutex> lock( mutex );
cond.wait( mutex );
}
//thread #2
while(1)
{
getchar();
for( int i = 0 ; i < 1000 ; ++i )
{
cb.push(new D(i)); //one producer so no lock required
cond.notify_one(); // no lock required here ?
}
}
要避免这种情况,您必须在消费者中:
mutex
cond.wait(互斥)代码>
mutex
cond.notify\u one()
编辑:另一方面,信号量可能更适合管理消息队列。具有反映队列中项目数的信号量。你每次
向上推和向下它,然后每次弹出(或者只是将它嵌入队列本身,这样如果队列为空,那么pop
只需等待某个东西出现即可)。你可以拥有任意数量的锁,但你会得到竞争条件
除非pop
和push
都受到与
等待
和通知
(并且在
决定等待和实际等待)。标准成语是:
producer consumer
while(cb.pop()) ...;
cb.push();
cond.notify_one();
cond.wait(); // OOPS. I missed the notification!
这更复杂,我看不出你能从中得到什么。只是
使用已知工作可靠的常用模式
FWIW:你的代码充满了竞争条件:对于初学者来说:pop
在线程1中失败,存在上下文切换,线程2执行推送
和通知
,然后返回线程1,执行等待
。
然后等待,尽管队列中有东西
我可以补充一点,几乎从来没有任何理由支持这样的类型
循环缓冲区来管理自己的互斥锁。粒度是
太低了。例外情况是,如果pop指令实际上一直等到
有些东西在那里,即(基于std::deque
):
T*循环缓冲::推送(标准::自动插入)
{
boost::unique_lock l(myMutex);
myQueue.push_back(in.get());
in.release();//只有在成功推回之后!
myCondition.notify_all();
}
std::auto_ptr CircularBuffer::pop()
{
boost::unique_lock l(myMutex);
while(myQueue.empty()){
myCondition.wait();
}
std::auto_ptr result(myQueue.front());
myQueue.pop_front();
返回结果;
}
(注意在接口中使用了auto_ptr
。一旦提供程序
将对象传递到队列中时,该对象不再具有访问权限
您似乎正在使用支持C++0x的编译器(通过使用nullptr
可以看出),但您仍然使用Boost中的线程库。为什么?我使用的是msvc2010,它不支持C++0X EntrelyMy data container是静态的,在我的上下文中,我有多个生产者和一个消费者。因此消费者是线程安全的,而procuder不是,所以我只需要一个互斥体来保护对生产者中容器的访问。但我的疑问是,在这种情况下,互斥的正确用法是什么?我是否应该使用相同的互斥来等待和等待生产者,还是不一定使用?我实际上认为必须这样做。解锁和开始等待必须是原子的,否则您可能会错过更新。@stefaanc:是的,您可能是对的,如果我在容器中放入条件变量,比如在push-an中放入notify_one,会更好
// thread #1
// ...
{
boost::unique_lock<boost::mutex> lock( mutex );
while ( !cb.pop( d ) )
cond.wait( mutex );
}
// process d
// thread #2
// ...
{
boost::unique_lock<boost::mutex> lock( mutex );
cb.push( new D(i) );
cond.notify_one();
}
boost::unique_lock<boost::mutex> lock( mutex );
while ( cb.pop( d ) ) {
lock.unlock();
// process d
lock.lock();
}
cond.wait( mutex );
T* CircularBuffer::push( std::auto_ptr<T> in )
{
boost::unique_lock<boost::mutex> l( myMutex );
myQueue.push_back( in.get() );
in.release(); // Only after the push_back has succeeded!
myCondition.notify_all();
}
std::auto_ptr<T> CircularBuffer::pop()
{
boost::unique_lock<boost::mutex> l( myMutex );
while ( myQueue.empty() ) {
myCondition.wait();
}
std::auto_ptr<T> result( myQueue.front() );
myQueue.pop_front();
return result;
}