在销毁 DLL 中的静态对象(但不是 .exe)之前,工作线程会被强制终止吗?

Vio*_*ffe 5 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;
} 
Run Code Online (Sandbox Code Playgroud)

它按预期工作 - 打印“线程正常完成:1”并且应用程序退出。

但是,如果我将此代码移至 DLL(创建一个空 DLL,从中导出一个函数,将该对象放置StaticThreadTest在 dll 的 .cpp 中,thread.startThread()从导出的函数调用并从 调用此导出的函数main.cpp),代码有时会打印“Thread优雅地完成:0”,但更多时候它只是挂在thread.join().

这种行为有记录吗?这是运行时的错误还是有意为之?

main.cpp值得注意的是:使用 v120 工具集编译的相同代码即使在(在 exe 中)也会 100% 挂起。似乎 v120 工具集中存在一个错误,而在 v140 中,它针对 .exe 进行了修复,但针对 .dll 进行了修复。

Rud*_*lis 1

似乎使用不同的同步机制而不是繁忙循环(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();
}
Run Code Online (Sandbox Code Playgroud)

但我仍然会研究是否可以让它挂起,std::atomic因为如果这是原因,那么它仍然是一个与退出std::thread::join()后调用的问题不同的问题。main