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
可能永远不会醒来。
我有以下项目结构:一个单例 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
可能永远不会醒来。