Boost::interprocess::interprocess_condition::wait在等待时不会自动解锁互

boost::interprocess::interprocess_condition::wait does not atomically unlock mutex while waiting

本文关键字:interprocess 解锁 在等待 condition wait Boost      更新时间:2023-10-16

正如当前的帖子标题所说,boost boost::interprocess::interprocess_condition::wait应该在等待时自动解锁互斥锁,但它没有。

在以下代码中:

boost::interprocess::scoped_lock< boost::interprocess::interprocess_mutex > state_access_lock(impl->state->state_access_mut);
impl->state->state_access_cond.wait(state_access_lock);

在VS2010进入调试模式时,我按下暂停,当我看到state_access_lock在等待时仍然被锁定时,我感到很惊讶。

但这不是boost的doc在这里说的。

有人有什么建议吗?

谢谢。

这是第一个线程:

void CSharedMemory::start(start_mode mode)
{
bool start_mut_locked = true;
impl->running = true;
impl->mode = mode;
stateMetaStruct* state = impl->proc_state;
boost::interprocess::scoped_lock< boost::interprocess::interprocess_mutex > state_access_lock(state->state_access_mut);
while(impl->running)
{
    state->data_written = false;
    while(!state->data_written)
    {
        if(start_mut_locked)
        {
            // We can now unlock and let other threads to send data.
            impl->start_mut.unlock();
            start_mut_locked = false;
        }
        state->state_access_cond.wait(state_access_lock); // wait here upon sharedmemory's state change
        boost::interprocess::offset_ptr< stateMetaStruct > s = impl->shm_obj.find< stateMetaStruct >(boost::interprocess::unique_instance).first;
        state = s.get();
        if(!state->data_written)
        {
            // Spurious wakeup.
            glm_debug("Spurious wakeup.");
        }
        if(this == state->data_written_by_proccess)
        {
            state->data_written = false;
            glm_debug("Ignoring my proper event.");
        }
    }
    if(impl->running)
    {
        // Got action from other process.
        const interprocess_actions state_action = state->action;
        if(DO_STOP == state_action) {
        }
        else if(DUMP_USERS_REQUEST == state_action) {
            impl->stateChangedListener->onDumpUsersRequest();
        }
        else if(DUMP_USERS_REPLY == state_action) {
        }
        else {
            glm_err("Unexpected state.");
        }
    }
   }
}

第二个线程尝试使用这个方法发送数据:

void CSharedMemory::sendDumpUsersRequest()
{
// Ensure shm is started.
boost::mutex::scoped_lock lk(impl->start_mut);
glm_debug("%s", __FUNCTION__);
boost::interprocess::offset_ptr< stateMetaStruct > s = impl->shm_obj.find< stateMetaStruct >(boost::interprocess::unique_instance).first;
stateMetaStruct* state = s.get();
boost::interprocess::scoped_lock< boost::interprocess::interprocess_mutex > state_access_lock(state->state_access_mut);
state->action = DUMP_USERS_REQUEST;
state->data_written = true;
state->data_written_by_proccess = this;
// Send request.
state->state_access_cond.notify_all();
}

行为是,当尝试获取scoped_mutex时,第二个线程阻塞,因为第一个线程正在等待它。

根据目前的评论,我想我可以推断出一个答案。

不要相信传递给interprocess_condition::wait()的scoped_lock的成员。interprocess_condition的约定(与interprocess_condition_any不同)表明,您只能将其与interprocess_mutex的锁一起使用。知道了这一点,条件变量就会把内部互斥锁从锁中取出来,比它不知道锁的情况下更有效地完成它的工作。

所以当要解锁互斥锁时,它不会在scoped_lock上调用unlock(),而是直接在互斥锁上调用。这对于内部实现来说是没问题的;不要在家里这样做。如果没有在互斥锁超出作用域之前重新锁定互斥锁,就会发生不好的事情。

换句话说,您在调试器中看到的行为并不表明存在问题。如果你有死锁,它一定在别的地方。

编辑

给出的实际代码中的条件变量对我来说看起来很好。我发现与start_mut的交互有点奇怪。你确定那部分没问题吗?