You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
By clicking “Sign up for GitHub”, you agree to our
terms of service
and
privacy statement
. We’ll occasionally send you account related emails.
Already on GitHub?
Sign in
to your account
见
feature_thread
分支
如果动态库内线程在卸载动态库(
DLL_THREAD_DETACH
)之前结束:
hModule.0F910000 lpReserved.006FFCC8
Process attach.
> 主线程开始
hModule.0F910000 lpReserved.00000000
Thread attach.
子线程开始
子线程第0次循环抢占;
子线程第1次循环抢占;
子线程第2次循环抢占;
子线程第3次循环抢占;
子线程第4次循环抢占;
子线程结束
hModule.0F910000 lpReserved.00000000
Thread detach.
> 主线程结束
hModule.0F910000 lpReserved.00000001
Process detach.
请按任意键继续. . .
如果线程调用了
ExitThread
来结束线程(线程函数返回时,系统也会自动调用
ExitThread
),系统查看当前映射到进程空间中的所有 DLL 文件映像,并用
DLL_THREAD_DETACH
来调用
DllMain
函数,通知所有的 DLL 去执行线程级的清理工作。
注意:如果线程的结束是因为系统中的一个线程调用了
TerminateThread
,系统就不会用值
DLL_THREAD_DETACH
来调用所有 DLL 的
DllMain
函数。
引用来源
如果线程函数耗时较长,即便代码中做了等待指示,但卸载动态库就好会发生莫名其妙的现象:
(等待指示放在动态库
全局变量/静态变量
的
析构
函数中,如果是在普通函数(
直接或间接被主程序调用,而只要函数调用未结束,就意味着动态库正在使用,不会卸载
)就会按部就班等线程函数执行结束)
hModule.0FC30000 lpReserved.0056F7AC
Process attach.
> 主线程开始
hModule.0FC30000 lpReserved.00000000
Thread attach.
子线程开始
子线程第0次循环抢占;
子线程第1次循环抢占;
子线程第2次循环抢占;
子线程第3次循环抢占;
子线程第4次循环抢占;
子线程第5次循环抢占;
子线程第6次循环抢占;
子线程第7次循环抢占;
子线程第8次循环抢占;
子线程第9次循环抢占;
> 主线程结束
hModule.0FC30000 lpReserved.00000001
Process detach.
请按任意键继续. . .
动态库中子线程被突然掐断
(强行结束)!
https://github.com/tnie/YDData2/issues/228
https://github.com/tnie/YDData2/issues/227
log4z
作者表示
暂时不会加动态库
除非明确主线程等待,否则都会被动态库强行结束?——非全局变量/静态变量的析构都在主线程之内,肯定会等;也只有全局变量、静态变量的析构会在主线程
main()
结束之后
可是如果不是动态库中的全局变量/静态变量,而是主程序中的就不存在被强行结束的困惑。
如果从未意识到上述状况的存在,那么理解下面这段话可能就有些困难:
Consider a DLL that creates worker threads as part of its initialization. Upon DLL cleanup, it is necessary to synchronize with all the worker threads to ensure that the data structures are in a consistent state and then terminate the worker threads.
Today, there is no straightforward way to completely solve the problem of cleanly synchronizing and shutting down DLLs in a multithreaded environment.
This section describes the current best practices for thread synchronizing during DLL shutdown.
引用来源
由以下描述看出,在
DllMain
中并无有效手段可以用来解决我们的问题。
By the time
DllMain
is called at process exit, all the process’s threads have
been forcibly cleaned up
and there is a chance that
the address space is inconsistent
. Synchronization
is not required
in this case. In other words, the ideal
DLL_PROCESS_DETACH
handler is empty.
引用来源
问题核心在于 DLL 什么时候卸载,为什么卸载 DLL 并未等其(指 DLL 中的)静态变量析构执行完毕。所以,问题变成了 crt 相关了。
如果动态库(启用线程)析构中不
join()
子线程,只是做些耗时操作:打印结果多样,以后者居多
hModule.0F630000 lpReserved.00EFF980
Process attach.
> 主线程开始
> 主线程结束
hModule.0F630000 lpReserved.00000000
Thread attach.
hModule.0F630000 lpReserved.00000001
Process detach.
子线程第0次析构倒计时;
子线程第1次析构倒计时;
子线程第2次析构倒计时;
子线程第3次析构倒计时;
子线程第18次析构倒计时;
子线程第19次析构倒计时;
请按任意键继续. . .
以下无
Process detach.
的情形可能源于创建线程后既没有
join()
也未
detach()
hModule.0F6D0000 lpReserved.0098F5B4
Process attach.
> 主线程开始
> 主线程结束
hModule.0F6D0000 lpReserved.00000000
Thread attach.
请按任意键继续. . .
In a Windows C++ DLL, all global objects (including static members of classes) will be constructed just before the calling of the
DllMain
with
DLL_PROCESS_ATTACH
, and they will be
destroyed
just
after
the call of the
DllMain
with
DLL_PROCESS_DETACH
.
摘自
答主用了 destroy 而非 destruct,两者等价还是另有玄机?
动态库中的全局变量、静态变量的析构在
DLL_PROCESS_DETACH
之后执行,而采用
Load-Time Dynamic Linking
(区别于
Run-Time Dynamic Linking
)方式的程序,
DLL_PROCESS_DETACH
即意味着进程结束(执行
exist()
?),所以分离的两者如果纠缠的?——会让析构执行到末尾,但也会杀掉所有线程?
If the process is terminating (the lpvReserved parameter is non-NULL), all threads in the process except the current thread either have exited already or have
been explicitly terminated
by a call to the
ExitProcess
function, which might leave some process resources such as heaps in an inconsistent state.
引用来源
在 dll 静态变量/全局变量的析构函数中指明 join() 的线程,进程退出时会被强行结束——这个到底是不是 msvc 的 bug?
https://stackoverflow.com/questions/42535990/worker-threads-are-forcibly-terminated-prior-to-the-destruction-of-static-object
使用除了 msvc2015 之外的编译器测试:
g++ (Debian 4.9.2-10) 4.9.2 执行结果满足预期,会完整执行 .so 中的线程函数
msvc2017 执行结果同 msvc2015
没有解决方案:
https://stackoverflow.com/questions/43110740/thread-created-by-static-object-deleted-before-dtor
It seems like you wanted to control the thread shutdown cleanly, did you work out a solution for that? – Phil Brubaker Apr 4 '17 at 1:40
unfortunately, no. The issue is that the thread is created from DLL static object. This object is destructed after the process already cleaned up all its threads. I found two clean, but not comfort solutions, and one comfort but dirty solution – Boris Bolshem Apr 4 '17 at 8:27
Clean - make a done() functions, the user of lib should call it before the process ends. Kill a thread in done() function.
Clean - User may wrap your object in its own object, and user's object should call done() function in its desctructor
Dirty - do not care- the process is finishing, just let it kill all the used resources (in my case it will work) – Boris Bolshem Apr 4 '17 at 8:30