gpt4 book ai didi

c++ - 线程在完成执行代码之前在动态库中中止

转载 作者:行者123 更新时间:2023-11-30 03:43:01 25 4
gpt4 key购买 nike

我正在开发一个与 C API 兼容的库。

在库中,将有一个对象的全局实例,该对象的成员是 std::thread。似乎由于某种原因,当 main 返回并调用 exit() 时,线程会自动终止/终止。如果代码在同一项目中使用(直接在可执行文件中而不是通过库),则不会发生这种情况。

我希望以下示例在无限循环中运行:while(1) {...}thread.join() 应该相互阻塞。当它与库一起使用时,它不会,当调用 CThread 的析构函数时,线程似乎已经被终止/完成。我在这里缺少什么?

CThread.h

#ifndef CTHREAD_H
#define CTHREAD_H

#ifdef EXPORT_C_THREAD
# define EXPORT_CTHREAD __declspec(dllexport) __cdecl
#else
# define EXPORT_CTHREAD __declspec(dllimport) __cdecl
#endif

void EXPORT_CTHREAD testFunc();

#endif

CThread.cpp

#include "CThread.h"

#include <thread>
#include <memory>

class CThread
{
std::thread m_thread;
void infiniteLoop()
{
while (1) {
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
}
public:
CThread()
{
m_thread = std::thread(&CThread::infiniteLoop, this);
}

~CThread()
{
m_thread.join();
}

};

std::unique_ptr<CThread> cthread;

void testFunc()
{
cthread = std::make_unique<CThread>();
}

ma​​in.cpp(这是在另一个项目中。我正在链接到上面的库。)

#include "CThread.h"

int main()
{
testFunc();
return 0;
}

更新

按照建议,我尝试在 DLL_PROCESS_ATTACH 期间初始化 DllMain() 函数中的 cthread 对象,并在 期间解除分配>DLL_PROCESS_DETACH。由于 DllMain() 函数将获取加载程序锁,因此我必须稍后初始化线程。但是,和以前一样,当“调用”DLL_PROCESS_DETACH 时线程已经中止。 DLL_THREAD_DETACH 不会在退出时被调用。

还有什么建议吗?谢谢!

最佳答案

我能够使用 VS2015 重现此行为。

问题出在 std::unique_ptr<CThread> pthread;作为一个全局对象。指针的删除与 main 的执行无关线。 dll 的全局数据和主机 exe 的全局数据不会以可预测的方式相互同步。引入线程时还有更多的复杂性,这些线程会在进程退出时停止。

正如您所注意到的,将所有代码移动到单个 exe 允许全局数据在 main 上适当同步线程。

要解决这个问题,您可以导出一个 RAII 样式的类来管理线程的执行,或者简单地提供一个“清除线程”或清理函数并将其导出;该函数将具有以下形式;

void cleanupData()
{
cthread = nullptr; // block waiting for thread exit
}

为了进一步协助客户端代码,仍然可以提供支持此“清晰线程”的 RAII 类,但无需从 dll 中导出它。

客户端 RAII 可以利用 std::unique_ptrstd::shared_ptr按要求。最简单的形式是这样的;

struct Cleanup {
Cleanup() = default;
Cleanup(Cleanup const&) = delete;
Cleanup& operator=(Cleanup const&) = delete;
Cleanup(Cleanup&&) = delete;
Cleanup& operator=(Cleanup&&) = delete;

~Cleanup() { cleanupData(); } // clean up the threads...
};

这需要与开始使用或从 dll 导入的数据的生命周期相关联。

并用作;

{
auto cleanup = std::make_unique<Cleanup>();
testFunc();
// ...
}

题外话在析构函数中,在你之前join()线程,测试以确保它是 joinable() .


鉴于更新;这可以更改或改进吗,即一旦执行离开就可以控制线程 main ? TL;DR,不。

以“旧新事物”成名的陈峰,引自here :

On the other hand, the C runtime library automatically calls ExitProcess when you exit the main thread, regardless of whether there are any worker threads still active. This behavior for console programs is mandated by the C language, which says that (5.1.2.2.3) “a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument.” The C++ language has an equivalent requirement (3.6.1). Presumably, the C runtime folks carried this behavior to WinMain for consistency.

什么是 ExitProcess() do

...

  1. All of the threads in the process, except the calling thread, terminate their execution without receiving a DLL_THREAD_DETACH notification.
  2. The states of all of the threads terminated in step 1 become signaled.
  3. The entry-point functions of all loaded dynamic-link libraries (DLLs) are called with DLL_PROCESS_DETACH.

...

特别是上面的第 1 点和第 3 点,到 std::unique_ptr<CThread> 的析构函数时运行时,线程已经停止并发出信号。一旦主线程调用了 ExitProcess(),就不能依赖后台线程执行,它们已经停止,操作系统正在清理与该进程关联的所有资源。


你在评论中提到;

I will use an IPC mutex within the thread so it's critical that is cleaned up properly.

如果问题是互斥量而不仅仅是线程,那么问题就会稍微安静一些。然后更容易将互斥锁提取到全局级别并允许 DllMain到(使用 DLL_PROCESS_ATTACH 等)来管理它。线程将被允许正常访问。可能有一些额外的代码来指示互斥体的状态,但也可以使用 dll 进行管理。

同时请记住,IPC 互斥机制通常包括一个“已放弃”状态,正是为了这个目的。如果互斥锁的持有者意外失败并放弃互斥锁,则在尝试访问互斥锁时,互斥锁的其余客户端会收到通知。

来自WIN32 Mutex :

If a thread terminates without releasing its ownership of a mutex object, the mutex object is considered to be abandoned. A waiting thread can acquire ownership of an abandoned mutex object, but the wait function will return WAIT_ABANDONED to indicate that the mutex object is abandoned...

关于c++ - 线程在完成执行代码之前在动态库中中止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36408581/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com