notify_one 没有在动态库中触发 condition_variable

notify_one not triggering condition_variable inside dynamic library

我有以下项目结构:一个单例 class(有一个处理线程在 condition_variable 中等待)从一个 dll 文件和一个引用单例的可执行文件中公开.通过 RAII,我预计在销毁单例(以及内部实现的销毁)时通知 condition_variable(带有 notify_one)。 这不会发生并且行为很奇怪:条件变量没有被触发,但是主线程以某种方式加入了。

来自 DLL 项目的文件:

Foo.h:

#pragma once
#ifdef FOODLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#pragma comment(lib,"FooDll.lib")
#endif

#include <thread>
#include <condition_variable>
#include <iostream>
#include <functional>

class Foo_Impl {
public:
Foo_Impl()
    :_done(false)
{
    _writeThread = std::thread(std::bind(&Foo_Impl::threadRun, this));
}

virtual ~Foo_Impl() {
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _done = true;
    }
    _cv.notify_one();

    if (_writeThread.joinable()) {
        _writeThread.join();
    }
    std::cout << "Joined";
}

void threadRun() {
    std::unique_lock<std::mutex> lock(_mutex);
    std::cout << "Prepare wait" << std::endl;
    _cv.wait(lock, [&] 
        {
            return _done.load();
        });

    std::cout << "Done thread" << std::endl;
}

std::atomic<bool> _done;
std::thread _writeThread;
std::mutex _mutex;
std::condition_variable _cv;
};


class DLL_API Foo {
private:
Foo_Impl* mp_impl;

public:

static Foo& getInstance() {
    static Foo instance;
    return instance;
}

private:
Foo()
    :mp_impl(new Foo_Impl())
{
}
~Foo()
{
    delete mp_impl;
}
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
};

Foo.cpp

#include "pch.h"
#include "Foo.h"

来自可执行文件的文件:

main.cpp

#include "../FooDll/Foo.h"

int main()
{
    Foo& foo = Foo::getInstance();
    std::this_thread::sleep_for(std::chrono::seconds(1)); //allow some time so threadRun is running and waiting
    return 0;
}

我正在 VS2019 上构建。 我收到的输出是:

Prepare wait
Joined

如果我没有通过 Dll 使用 Foo class,而是 link 它与可执行文件 (class DLL_API Foo) 收到的输出是:

Prepare wait
Done thread
Joined

VS2013 上,对于 DLL 版本,我得到相同的输出:

Prepare wait
Joined

但对于非 Dll,线程永远不会加入:

Prepare wait
Done thread

EDITS : 向 condition_variable 添加谓词并在标记时锁定 bool 守卫。

您使用的条件变量不正确。

_cv.wait(lock) 可以在有或没有通知的情况下随时醒来。您需要将谓词与条件变量相关联,并手动将其包装在循环中,或者使用 wait:

的谓词重载

_cv.wait(lock,[&]{return flag;});,其中flag是一个bool在持有锁的时候设置的关机代码,通知前:

~Foo_Impl() {
    {
        std::lock_guard guard(_mutex);
        flag=true;
    }
    _cv.notify_one();

    if (_writeThread.joinable()) {
        _writeThread.join();
    }
    std::cout << "Joined";
}

如果不这样做,那么不仅 wait 可能不会等待,而且 notify_one 调用可能根本不做任何事情,因此 wait 可能永远不会醒来。