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

C++ Unlocking a std::mutex before calling std::unique_lock wait

本文关键字:std mutex 等待 解锁 调用 unique C++ lock      更新时间:2023-10-16

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

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

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"在线程等待时仍然被锁定。因此,不能通过并发线程在当前线程的 deque 中添加任何对象。

所以我把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()"指令之后执行。有谁知道使用标准库创建如此关键指令序列的方法?

提前谢谢。

最好不要

假设,当您从等待条件变量返回时,您等待的条件已满足

我宁愿将此代码编写为:

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();
}

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