考虑以下代码。以下所有内容均使用 v140 C++ 运行时在 Visual Studio 2015 中编译和执行:
#include <thread>
#include <atomic>
#include <sstream>
#include <Windows.h>
struct StaticThreadTest
{
~StaticThreadTest()
{
_terminationRequested = true;
if (_thread.joinable())
_thread.join();
std::ostringstream ss;
ss << "Thread finished gracefully: " << _threadFinishedGracefully << "\n";
OutputDebugStringA(ss.str().c_str());
}
void startThread()
{
_thread = std::thread([&]() {
while (!_terminationRequested);
_threadFinishedGracefully = true;
});
}
std::thread _thread;
std::atomic<bool> _terminationRequested {false};
std::atomic<bool> _threadFinishedGracefully {false};
};
static StaticThreadTest thread;
int main()
{
thread.startThread();
return 0;
}
它按预期工作 - 打印“Thread finished gracefully: 1”并退出应用程序。
但是,如果我将此代码移动到 DLL(创建一个空 DLL,从中导出一个函数,将 StaticThreadTest
对象放在 dll 的 .cpp 中,调用 thread.startThread( )
并从 main.cpp
调用此导出函数),代码有时会打印“Thread finished gracefully: 0”,但更多时候它只是卡在 thread.join()
.
是否记录了此行为?这是运行时中的错误还是有意为之?
注意:即使在 main.cpp
(在 exe 中)中,使用 v120 工具集编译的相同代码也会在 100% 的时间内挂起。似乎 v120 工具集中存在错误,而在 v140 中它已针对 .exe 修复,但未针对 .dll 修复。
最佳答案
似乎使用不同的同步机制而不是繁忙的循环(std::mutex
+ std::condition_variable
)可以消除这种情况。
以下示例演示了这两种机制:
#include "thread-test-dll.h"
#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
//#define _BUSY_WAIT
#ifdef _BUSY_WAIT
#include <atomic>
#endif
class foo
{
public:
foo()
#ifdef _BUSY_WAIT
: termination_requested_(false),
terminated_gracefully_(false)
#endif
{
std::cout << "foo::foo()...\n";
}
void run()
{
#define _USE_LAMBDA
#ifdef _USE_LAMBDA
thread_ = std::thread([&]() {
work();
});
#else
thread_ = std::thread(&foo::work, this);
#endif
}
~foo()
{
std::cout << "foo::~foo()...\n";
if (thread_.joinable())
{
#ifdef _BUSY_WAIT
termination_requested_ = true;
#else
condition_variable_.notify_all();
#endif
thread_.join();
std::cout << "thread joined...\n";
}
else
{
std::cout << "thread was not joinable...\n";
}
#ifdef _BUSY_WAIT
std::cout << "terminated_gracefully_ = " << terminated_gracefully_ << "\n";
#endif
}
void work()
{
#ifdef _BUSY_WAIT
while (!termination_requested_);
terminated_gracefully_ = true;
#else
std::unique_lock<std::mutex> mutex_lock(mutex_);
condition_variable_.wait(mutex_lock);
#endif
std::cout << "foo:work() terminating...\n";
}
private:
#ifdef _BUSY_WAIT
std::atomic<bool> termination_requested_;
std::atomic<bool> terminated_gracefully_;
#endif
std::thread thread_;
std::mutex mutex_;
std::condition_variable condition_variable_;
};
static foo instance;
void runThread()
{
instance.run();
}
但我仍然会研究是否可以让它与 std::atomic
一起挂起,因为如果这是原因,它仍然是一个与调用 std 的问题不同的问题: :thread::join()
在 main
退出后。
关于c++ - 工作线程在 DLL(但不是 .exe)中的静态对象被破坏之前被强制终止?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42535990/