为啥 Main 函数上的 Sleep() 会停止所有线程?

Posted

技术标签:

【中文标题】为啥 Main 函数上的 Sleep() 会停止所有线程?【英文标题】:Why Sleep() on Main function stop all threads?为什么 Main 函数上的 Sleep() 会停止所有线程? 【发布时间】:2019-11-08 10:38:50 【问题描述】:

为什么Sleep() 会停止所有创建的线程?我想创建一个线程,但在线程完成之前让Main 函数处于睡眠状态。

bool _finished = false;

void testcount(void *p)
 int i = 0;
 while(i<=30)
  i++;
  std::cout<<i<<"\n";
  Sleep(1000);
 
_finished = true;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 HANDLE test = NULL;
 test = CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)testcount, NULL, NULL, NULL);
 if(test)
  std::cout<<"test thread created";
 CloseHandle(test);

 while(!_finished)
  Sleep(1000);

return true;

我现在正在尝试这样,但程序永远不会完成,因为whileSleep 会停止线程。我不想在线程未完成时在Main 上返回任何内容。有什么解决办法吗?

【问题讨论】:

在做线程之前,请阅读 DllMain 上的文档 在新线程的代码到达 testcount 之前 - 它会尝试使用 DLL_THREAD_ATTACH 调用 dlls 入口点。内部临界区(加载程序锁)。但你的第一个线程持有这个关键部分 - 在这里等待。结果-您的新线程将等到父线程释放加载程序锁定。但它一直等到_finished - 永远如此。死锁 来自@engf-010 的好建议。旧的但写得很好的文章应该会给你一个很好的理解。 devblogs.microsoft.com/oldnewthing/?p=25283 Dynamic-Link Library Best Practices: "你不应该在 DllMain 中执行以下任务:[...] 调用 CreateThread。创建线程可以工作 如果你不与其他线程同步线程". 【参考方案1】:

    DllMain 的调用由 Win32 序列化。

    所有新线程都从调用DllMain(带有线程附加标志)开始,并将调用方法传递给CreateThread

因此,您的线程正在等待调用 DllMain,这在您的第一个线程离开 DllMain 之前不会发生。

正如评论者 John Sheridan 所说,Raymond Chen's blog post from 2007 是一个非常好的解释。

PS。对于正确的 C/C++ 库初始化,您应该直接使用 _beginthread or _beginthreadex 而不是 CreateThread

【讨论】:

@han:一个问题在 17 年前得到解决(导致内存泄漏)。还存在另一个问题(在内存不足的情况下程序终止),因此如果您在该线程上使用 CRT 功能,则需要使用 CRT 函数来创建线程。【参考方案2】:

新线程被阻塞,因为您的主线程没有离开DllMain,如理查德的回答中所述。

您的代码还包含数据竞争,并且即使在此死锁被修复后仍具有未定义的行为。新线程写入_finished,主线程同时读取_finished。假设 C++11 可用,您可以尝试使用 std::atomic&lt;bool&gt; 而不是 bool 来解决此问题,或者您可以使用 Win32 原语进行线程同步。

使用std::atomic&lt;bool&gt; 更改标准解决方案:

#include <atomic>

std::atomic<bool> finished_false;

// Rest remains the same

【讨论】:

不是那个,OP似乎对DllMain一无所知 完全不相关。 testcount 从未开始执行。 这不是无关的,不是第一个触发的bug,而是UB。 IE。即使初始化死锁被修复,一切皆有可能。特别是,编译器可以优化 while 循环中的检查。 @engf-010 - 真正的新线程将等待使用DLL_THREAD_ATTACH进入加载程序锁 @engf-010 - 完成 - 新线程在开始执行时开始无限等待 - 尝试获取加载程序锁时。甚至testcount 也永远不会开始执行。说线程退出没有意义。

以上是关于为啥 Main 函数上的 Sleep() 会停止所有线程?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Sleep() 函数会阻止整个循环工作?

为啥我的代码停止并且不返回异常?

为啥 THREE.ColladaLoader 会停止网站上的所有活动?

Windows 10上的Java Thread.sleep()在S3睡眠状态下停止

为啥 Visual Studio 2010 (Intellisense) 会停止生成接口指针?

pythony中子进程如果一定时间不结束就停止应该如何做?