为啥 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;
我现在正在尝试这样,但程序永远不会完成,因为while
和Sleep
会停止线程。我不想在线程未完成时在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<bool>
而不是 bool
来解决此问题,或者您可以使用 Win32 原语进行线程同步。
使用std::atomic<bool>
更改标准解决方案:
#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() 会停止所有线程?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 THREE.ColladaLoader 会停止网站上的所有活动?
Windows 10上的Java Thread.sleep()在S3睡眠状态下停止