boost::wait和boost::condition必须共享同一个互斥对象吗?
does boost::wait and boost::condition have to share the same mutex object
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文档指定,如果它是ok的?
否则,thread1是消费者,如果我只有一个线程"消费",似乎等待所需的锁有点多余,不是吗?
EDIT:我不关心错过的更新。当我接收到更新时,我用接收到的数据更新对象。我只想要更新鲜的更新,不一定是所有的更新
可以有任意多的锁,但是会出现竞争条件除非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 );
它更复杂,我看不出你能从中得到什么。只是使用通常的模式,这是已知可靠的。
fww:你的代码充满了竞争条件:对于初学者:pop
线程1失败,有一个上下文切换,线程2做push
和notify
,然后返回到执行cond.wait
的线程1。然后等待,尽管队列中有东西。
我可以补充一点,对于像这样的类型几乎没有任何正当理由循环缓冲区来管理它们自己的互斥锁。粒度为太低了。例外情况是,如果pop指令实际上等待,直到有些东西在那里,即(基于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;
}
(注意在接口中使用了auto_ptr
。一旦提供者将对象传递到队列中,它不再具有访问权限它。)
condvar必须使用保护数据的互斥锁(好吧,不完全是,下面更详细),否则您将错过更新:
producer consumer
while(cb.pop()) ...;
cb.push();
cond.notify_one();
cond.wait(); // OOPS. I missed the notification!
要避免这种情况,必须在消费者中:
- 锁
mutex
- 验证条件不满足
-
cond.wait(mutex);
- 返回验证条件(
mutex
再次锁定)
和producer中必须:
- 锁
mutex
- 使条件为真(即cb.push())
-
cond.notify_one()
现在你终于可以解锁
mutex
了。所以它不一定是保护数据的锁,但是你必须在最后一次检查和等待中锁定,在生产者中设置条件和通知。
顺便说一句,实际上可以创建一个不需要与锁配合的通知机制。它需要对"为信号注册"answers"等待信号"进行单独的操作,后者在第一个信号出现后立即返回(并检查它们之间的条件)。然而,我还没有在任何可移植的线程库中看到这样的机制。
Edit:另一方面,信号量可能更适合于管理消息队列。具有反映队列中项目数量的信号量。您可以在每个push
和down
之前为每个pop
添加up
(或者只是将其嵌入队列本身,因此pop
将简单地等待如果队列为空出现的内容)。
如果环缓冲区的push
和pop
函数是线程安全的,那么您不需要额外的同步。
通常,应该使用条件变量来表示线程之间共享的条件,因此应该以线程安全的方式访问条件。但是,互斥锁需要在等待时解锁,以便其他线程可以更改条件。请看这里的一个使用队列的例子。
在你的例子中,你已经有了一个线程安全容器。把条件变量放在容器中并让它使用它的互斥量不是更好吗?
- 理解boost::asio-async_read在无需读取内容时的行为
- boost::进程间消息队列引发错误
- 如何运行位于boost/libs/python/example/tutorial目录中的hello.cpp和Jamfil
- cmake如何在fedora工作站中找到boost静态库包
- CMake项目Boost库错误:Boost/config/compiler/gcc.hpp:165:10:致命错误:cs
- Boost Graph Library,修复节点大小
- 什么是"#include <boost/functional/hash.hpp> "?
- 基于boost的程序的静态链接——zlib问题
- C++:如何在CLion IDE中安装Boost
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 如何在boost beast http请求中设置http头
- Boost Spirit,获取迭代器内部语义动作
- boost::asio::steady_timer()与sleep()我应该使用哪一个
- boost::asio如何生成多个协同程序,然后加入它们
- 为什么std::async使用同一个线程运行函数
- 为什么 boost 文件系统和 libpq-fe 标头不会在同一个文件中编译
- 如何使用Boost.Filesystem检查两个路径是否指向同一个文件/目录
- c++: Boost::asio:在同一个函数中等待异步处理程序
- boost:: posix_time.如何在同一个应用程序中表示微秒和纳秒日期时间
- boost::wait和boost::condition必须共享同一个互斥对象吗?