boost :: wait和boost :: condition必须共享相同的互斥对象

Gui*_*e07 5 c++ multithreading boost c++11

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 ?
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道如果我的数据容器有自己的锁以避免数据竞争是否可以,另一方面boost :: wait使用他的锁/互斥机制,因为它由boost文档指定?

否则,thread1是消费者,如果我只有一个"完全"的线程,似乎等待所需的锁有点多余,不是吗?

编辑:我不关心缺少更新.当我收到更新时,我用接收的数据更新一个对象.我只想要更新的更新,而不是所有的udpate

Jam*_*nze 2

您可以拥有任意数量的锁,但您会遇到竞争条件,除非 和pop都受到与和push相同的互斥锁的保护 (并且在决定等待和实际等待之间不会释放锁) 。标准的习语是:waitnotify

//  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();
}
Run Code Online (Sandbox Code Playgroud)

尝试在pop线程 #1 上循环更加复杂,至少如果您想在处理d. 你需要类似的东西:

boost::unique_lock<boost::mutex> lock( mutex );
while ( cb.pop( d ) ) {
    lock.unlock();
    //  process d
    lock.lock();
}
cond.wait( mutex );
Run Code Online (Sandbox Code Playgroud)

它更复杂,我不知道你能从中得到什么。只需使用通常的模式即可,众所周知,这种模式可以可靠地工作。

FWIW:您的代码充满了竞争条件:对于初学者:pop 线程 1 中失败,有一个上下文切换,线程 2 执行pushnotify,然后回到线程 1,执行cond.wait。并等待,尽管事实上队列中有东西。

我可能会补充一点,像循环缓冲区这样的类型几乎没有任何理由来管理自己的互斥锁。粒度太低。例外情况是 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;
}
Run Code Online (Sandbox Code Playgroud)

(注意接口中的使用auto_ptr。一旦提供者将对象传递到队列中,它就不再有权访问它。)