C ++在调用std :: unique_lock wait之前解锁std :: mutex

时间:2012-06-11 22:25:51

标签: c++ locking race-condition stdthread

我有一个多线程应用程序(使用std :: thread)和一个管理器(类Tree),它在不同的子树(嵌入式struct SubTree)上并行执行一些代码。基本思想是SubTree的每个实例都有一个存储对象的双端队列。如果deque为空,则线程将等待,直到在deque中插入新元素或达到终止条件。一个子树可以生成对象并将它们推送到另一个子树的双端队列中。为方便起见,我的所有std :: mutex,std :: locks和std :: variable_condition都存储在一个名为“locks”的结构中。

类Tree创建一些运行以下方法的线程(第一次尝试):

void Tree::launch(SubTree & st, Locks & locks )
{
/* some code */

std::lock_guard<std::mutex> deque_lock(locks.deque_mutex_[st.id_]) ; // lock the access to the deque of subtree st
if (st.deque_.empty())  // check that the deque is still empty
{
    // some threads are still running, wait for them to terminate

    std::unique_lock<std::mutex> wait_lock(locks.restart_mutex_[st.id_]) ;
    locks.restart_condition_[st.id_].wait(wait_lock) ;   
}

/* some code */
}

问题是在线程等待时“deque_lock”仍然被锁定。因此,当前线程的双端队列中不能添加任何对象。

所以我将lock_guard转换为unique_lock并手动管理锁定/解锁:

void launch(SubTree & st, Locks & locks )
{
/* some code */

std::unique_lock<std::mutex> deque_lock(locks.deque_mutex_[st.id_]) ; // lock the access to the deque of subtree st
if (st.deque_.empty())          // check that the deque is still empty
{
    deque_lock.unlock() ; // unlock the access to the deque to enable the other threads to add objects

    // DATA RACE : nothing must happen to the unprotected deque here !!!!!!

    // some threads are still running, wait for them to terminate

    std::unique_lock<std::mutex> wait_lock(locks.restart_mutex_[st.id_]) ;
    locks.restart_condition_[st.id_].wait(wait_lock) ;   
}

/* some code */
} 

现在的问题是存在数据竞争,我想确保在“deque_lock.unlock()”之后直接执行“wait”指令。有谁知道用标准库创建这样一个关键指令序列的方法?

提前致谢。

1 个答案:

答案 0 :(得分:0)

这是一个很好的做法不要假设,当你等待一个条件变量返回时,你所等待的条件是否满足

我宁愿把这段代码写成:

std::unique_lock<std::mutex> deque_lock(locks.deque_mutex_[st.id_]);
while(st.deque_.empty())
{
    deque_lock.unlock();
    std::unique_lock<std::mutex> wait_lock(locks.restart_mutex_[st.id_]);
    locks.restart_condition_[st.id_].wait(wait_lock);   
    deque_lock.lock();
}

此代码保证,在您的队列不为空之后。 std::condition_variable::wait甚至可以使用谓词来模拟这种行为之王(但是,由于队列锁定,它不能在这里使用)。