c++ - 工作线程在 DLL(但不是 .exe)中的静态对象被破坏之前被强制终止?

标签 c++ windows multithreading c++11 visual-studio-2015

考虑以下代码。以下所有内容均使用 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/

相关文章:

C++/将 std::string 和 wchar* 连接到 wchar*

Python线程定时器问题

c++ - 结构复制标准吗?

java - 为什么 "Set()"功能比修改公共(public)变量更好?

c# P/调用 : Pass Enum value with IntPtr to Function; AccessViolationException

python - matplotlib 在 Windows 上的 Python 2.7.3 中中断 str( )

c - 堆栈溢出在 Linux 上静音?

windows - ros::init(...) 抛出错误 - Windows roscpp

c++ - 线程设计和设计以及在 C++ Win32 中从另一个线程中调用一个函数

android - RxJava 在主线程中运行部分平面图