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 ?
}
}
我想知道如果我的数据容器有自己的锁来避免数据竞争是否可以,另一方面 boost::wait 使用他的锁/互斥机制,正如 boost 文档所指定的那样?
否则,线程 1 是消费者,如果我只有一个线程“消费”,那么 wait 所需的锁似乎有点多余,不是吗?
编辑:我不关心丢失的更新。当我收到更新时,我用收到的数据更新一个对象。我只想要更新鲜的更新,而不是所有更新
最佳答案
你可以拥有任意数量的锁,但你会遇到竞争条件
除非 pop
和 push
都受到与
wait
和 notify
(并且锁在
决定等待和实际等待)。标准的成语是:
// 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();
}
尝试在线程 #1 中的 pop
上循环更复杂,至少
如果你想在 d
的处理过程中释放锁。你需要
像这样的东西:
boost::unique_lock<boost::mutex> lock( mutex );
while ( cb.pop( d ) ) {
lock.unlock();
// process d
lock.lock();
}
cond.wait( mutex );
它更复杂,我看不出你能从中得到什么。只是 使用已知的可靠工作的常用模式。
FWIW:您的代码充满了竞争条件:对于初学者:pop
线程 1 失败,有一个上下文切换,线程 2 执行 push
和 notify
,然后返回到执行 cond.wait
的线程 1。
等待,尽管队列中有东西。
我可能会补充说,几乎没有任何理由支持像这样的类型
循环缓冲区来管理自己的互斥锁。粒度是
太低。异常(exception)情况是弹出指令实际上等到
那里有东西,即(基于 std::deque
):
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;
}
(注意接口(interface)中auto_ptr
的使用。一旦提供者有
将对象传入队列,它不再有访问权限
它。)
关于c++ - boost::wait 和 boost::condition 是否必须共享相同的互斥对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6923641/