首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >销毁条件变量随机丢失通知

销毁条件变量随机丢失通知
EN

Stack Overflow用户
提问于 2018-01-04 10:55:00
回答 2查看 1.4K关注 0票数 17

如果condition_variable是一个类的成员,我的理解是:

  1. 条件变量在类析构函数完成后被销毁。
  2. 条件变量的销毁不需要等待收到通知。

根据这些预期,我的问题是:下面的示例代码为什么不通知等待线程?

代码语言:javascript
复制
#include <mutex>
#include <condition_variable>
#define NOTIFY_IN_DESTRUCTOR 

struct notify_on_delete {
    std::condition_variable cv;

    ~notify_on_delete() {
#ifdef NOTIFY_IN_DESTRUCTOR
        cv.notify_all();
#endif
    }
};

int main () {
    for (int trial = 0; trial < 10000; ++trial) {
        notify_on_delete* nod = new notify_on_delete();
        std::mutex flag;
        bool kill = false;

        std::thread run([nod, &flag, &kill] () {
            std::unique_lock<std::mutex> lock(flag);
            kill = true;
            nod->cv.wait(lock);
        });

        while(true) {
            std::unique_lock<std::mutex> lock(flag);
            if (!kill) continue;
#ifdef NOTIFY_IN_DESTRUCTOR
            delete nod;
#else
            nod->cv.notify_all();
#endif
            break;
        }
        run.join();
#ifndef NOTIFY_IN_DESTRUCTOR
        delete nod;
#endif
    }
    return 0;
}

在上面的代码中,如果没有定义NOTIFY_IN_DESTRUCTOR,那么测试将可靠地运行到完成。然而,当定义NOTIFY_IN_DESTRUCTOR时,测试将随机挂起(通常在几千次试验之后)。

我正在使用Apple : Apple版本9.0.0 (clang-900.0.39.2)进行编译,目标: x86_64-apple-darwin17.3.0线程模型: posix指定的C++14,使用设置的调试标志进行编译。

编辑:

为了澄清:这个问题是关于condition_variable实例的指定行为的语义。上面的第二点似乎在下面的报价中被重新执行

封锁要求:不会有线程阻塞*这。 注意事项:也就是说,所有线程都应已被通知;它们随后可能会阻塞等待中指定的锁。这就放松了通常的规则,这就要求所有的等待呼叫发生在毁灭之前。只有解除阻塞的通知才需要在销毁之前发生。用户应该注意确保在析构函数启动后没有线程等待*这一点,特别是当等待线程在循环中调用等待函数或使用接受谓词的wait、wait_­for或wait_­until的重载时。- end注意事项 

核心的语义问题似乎是“阻止”的意思。我现在对上述引文的解释是,在行之后

代码语言:javascript
复制
cv.notify_all(); // defined NOTIFY_IN_DESTRUCTOR

在~notify_on_delete()中,线程测试没有在nod上被“阻塞”--也就是说,我目前理解在调用“取消阻塞等待的通知”之后发生了,因此根据引号,已经满足了继续销毁condition_variable实例的要求。

有人能澄清“阻塞的”或“取消阻塞的通知”,大意是在上面的代码中,对notify_all()的调用不符合~condition_variable()的要求吗?

EN

Stack Overflow用户

发布于 2018-01-04 11:18:19

定义NOTIFY_IN_DESTRUCTOR时:

调用notify_one()/notify_all()并不意味着等待线程立即被唤醒,当前线程将等待另一个线程。这只是意味着,如果等待线程在当前线程调用通知之后的某个时刻醒来,它应该继续进行。因此,本质上,您可能是在等待线程唤醒之前删除条件变量(取决于线程的调度方式)。

对于为什么挂起的解释,即使在其他线程等待时删除了条件变量,也取决于等待/通知操作是使用与条件变量关联的队列实现的。这些队列保存等待条件变量的线程。释放条件变量将意味着摆脱这些线程队列。

票数 9
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48093715

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档