Рабочие потоки, работающие в DLL, уничтожаются при завершении работы приложения, прежде чем их можно будет корректно завершить - PullRequest
0 голосов
/ 30 января 2019

Мне по какой-то причине нужен глобальный объект в .dll, который управляет std::thread.Это реализовано следующим образом:

#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).

И из-за этого факта ( Source0 , Source1 ), приложение блокируется при вызове m_cv.notify_one ();, если используется Windows 7 (не блокируется в Windows 8 и выше).

Факт,то, что он блокируется в одной конкретной версии 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 голосов
/ 30 января 2019

Когда возвращается WinMain, среда выполнения вызывает ExitProcess.Первое, что делает: «1. Все потоки в процессе, кроме вызывающего потока, прекращают свое выполнение без получения уведомления DLL_THREAD_DETACH».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...