在DLL中运行的辅助线程会在应用程序关闭时被杀死,然后才能正常关闭它们

时间:2019-01-30 15:47:00

标签: c++ windows multithreading c++11 dll

出于某种原因,我需要在管理std::thread的.dll中有一个全局对象。它是通过以下方式实现的:

#include "Header.h"
#include <thread>
#include <condition_variable>
#include <mutex>

class Foo
    {
public:
    Foo () : m_closeThread (false)
        {
        m_thread = std::thread (&Foo::ThreadProc, this);
        }

    ~Foo ()
        {
            {
            std::unique_lock<std::mutex> lock (m_mutex);
            m_closeThread = true;
            }

        m_cv.notify_one ();
        m_thread.join ();
        }

private:
    void ThreadProc ()
        {
        while (true)
            {
            std::unique_lock<std::mutex> lock (m_mutex);
            m_cv.wait (lock, [this] () { return m_closeThread; });
            if (m_closeThread)
                break;
            }
        }

private:
    bool m_closeThread;
    std::thread m_thread;
    std::condition_variable m_cv;
    std::mutex m_mutex;
    };

Foo& GetFoo ()
    {
    static Foo foo;
    return foo;
    }

extern "C" void Function ()
    {
    auto& foo = GetFoo ();
    }

但是,当关闭应用程序时,在执行~Foo之前 时,.dll的所有工作线程都会被杀死,或者如MSVS2015的输出窗口所述:

  

线程0x1040已退出,代码为0(0x0)。

并且由于这一事实(Source0Source1),如果使用Windows 7,则该应用程序会在m_cv.notify_one ();调用时阻塞(在Windows 8及更高版本上不会阻塞)

事实上,它阻止在一个特定版本的Windows上,而不是在其他特定版本的Windows上,使我认为,应该归咎于某种类型的UB(例如与DLL卸载顺序相关的问题,因为如果这样的问题不能重现,对象不在.dll中),但是我没有想到解决方案,该解决方案使我可以优雅地关闭线程,同时使对象成为全局对象(因为,需要进行主要的应用程序重组,以使其变为非全局对象)。

那么,在Windows平台杀死线程之前,可以优雅地关闭线程吗?

注释0:

为了示例完整性,

这是DLLMain:

#include <Windows.h>

BOOL APIENTRY DllMain (HMODULE, DWORD, LPVOID) { return TRUE; }

这是.dll的标题:

#pragma once
extern "C" void Function ();

这是控制台应用程序,使用上述.dll:

#include "..\Test\Header.h"
#include <chrono>
#include <thread>

int main ()
    {
    Function ();
    using namespace std::chrono_literals;
    std::this_thread::sleep_for (2s);
    }

注释1:

我目前最多只能使用C ++ 11(或MSVS 2015中提供的任何功能)。

1 个答案:

答案 0 :(得分:1)

$('#table1, table2, table3').dataTable({ initComplete: function() { var column = this.api().column(0); var $targetFilter = $(this).prev('.selectTriggerFilter'); var select = $('<select class="filter"><option value=""></option></select>') .appendTo($targetFilter) .on('change', function() { var val = $(this).val(); column.search(val).draw() }); } }); 返回时,运行时将调用ExitProcess。要做的第一件事是“ 1.进程中的所有线程(调用线程除外)都终止其执行,而没有收到WinMain通知。”