文章目录[隐藏]
封装多线程模块-api-线程的挂起和恢复销毁
强制杀死或挂起线程会导致线程正在获取的锁资源无法释放;如果正在操作一块公共内存,可能会导致公共内存被破坏。
一、SuspendThread
在实际环境中,调用SuspendThread时必须小心,因为不知道暂停线程运行时它在进行什么操作。如果线程试图从堆栈中分配内存,那么该线程将在该堆栈上设置一个锁。当其他线程试图访问该堆栈时,这些线程的访问就被停止,知道第一个线程恢复运行 。只有确切知道目标线程是什么(或者目标线程正在做什么),并且采取强有力的措施来避免因暂停线程的运行而带来的问题或死锁状态,suspendThread才是安全的。
二、ResumeThread
使线程的挂起时间计数减一。创建一个挂起的线程或者手动挂起一个线程后调用。调用该函数后线程不一定会立刻执行,而是由操作系统继续调度,直到计数为0,系统为其分配资源时才开始执行。
ResumeThread函数并不能保证线程真地继续执行,为什么呢?每一个线程都有一个线程暂停计数器,当线程正在运行时计数器为0,当其他线程对此线程使用SuspendThread函数时计数器会增加1,调用ResumeThread会使计数器减小1,所以当调用SuspendThread函数后计数器变为1。但是Windows是一个多线程操作系统,所以很有可能某个其他的线程也对此线程调用了SuspendThread,这时计数器就会变为2,这时再调用ResumeThread只会使计数器变回为1,线程将继续暂停,直到计数器变为0。那么,如何确定线程是否真地被继续执行了呢?很简单,检查函数返回值就可以了。如果返回值为0,则表示线程已经恢复执行了,如果不为0,则表示线程继续被暂停,如果为0xffffffff,则说明函数调用失败了。
三、忠告建议:
1、如果线程正在进行堆分配时被强行撤销,可能会破坏堆,造成堆锁没有释放,如果这时其他线程进行堆分配就会陷入死锁。
2、来之MSDN的血淋淋的警告:
a. If the target thread owns a critical section, the critical section will not be released.(如果目标线程持有着一个临界区(critical section),这临界区将不会被释放。)
b. If the target thread is allocating memory from the heap, the heap lock will not be released. (如果目标线程正在堆里分配内存,堆锁(heap lock)将不会被释放。)
c. If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent. (如果目标线程在结束时调用了某些kernel32,会造成kernel32的状态不一致。)
d. If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL. (如果目标线程正在更改一个共享DLL的全局状态,这个共享DLL的状态可能会被破坏,影响到其他的正在使用这个DLL库的线程。
四、大漠建议:
' 然后我们说一下系统的多线程
' 系统的多线程其实就是创建,暂停,恢复,强制结束这4个接口
' 先告诉大家结论,暂停这个接口,永远不要去调用. 强制结束这个接口要尽可能避免调用.
' 很多用户为了方便,在暂停某个脚本时,使用了系统提供的暂停接口
' 结果导致了各种卡死,崩溃。 还不知道咋回事。 感觉明明代码写的没毛病啊
' 这里我要说一下,系统提供的暂停(SuspendThread)操作,压根就不是给正常用户使用的,这是给调试器使用的
' 那为何这个暂停操作会导致异常呢? 实际上,线程在运行当中,它的状态是不可控的
' 假如你要暂停的线程正好处于某个锁当中(E语言也叫做许可证),万一恰巧这个锁还是个全局的,你说会发生什么事情?
' 而恰巧的是,系统中使用全局锁的操作很频繁. 比如分配内存/释放内存.
' 所以我给大家的建议是,永远不要去用暂停这个接口.
' 至于强制结束线程,也是非常不建议使用,它和暂停线程有相同的作用. 假如结束的线程正好处于锁当中,BOOM!!!
' 那么今天的例子也就是给大家演示,如何不用这几个要命的接口,如何正确的使用多线程.
' 至于上面说的暂停,恢复我们有别的方法替代完成.
五、最后总结
1、不要调用 SuspendThread 暂停线程,不要用 TerminateThread 结束线程, 造成死锁的情况。
2、win32下的API基本都是线程安全的,因此API里面有很多线程同步的地方,LoadLibrary里面有一个临界区,线程函数在执行到LoadLibrary里面之后,如果刚好走到LoadLibrary的临界区里面,此时主线程的ontimer触发,将该线程挂起,ontimer继续执行,运行到LoadLibrary后,由于线程中LoadLibrary还没有从临界区出来,此时就造成主线程ontimer里面的LoadLibrary无限等待,主线程挂起。
3、因此不建议用suspend暂停线程,MSDN也有说明,suspend最好只在debug里面使用。
4、那怎么使线程挂起呢?监视线程的状态。
优酷全部教程播单:http://i.youku.com/i/UNTU3NDYyODg0/playlists
交流群:521068947
本人QQ: 272586593