前言:
Windows环境下线程的终止有别于Linux,Linux可以通过发信号的方式通知相应线程终止,也可以通过线程终止函数来终止线程,这两种方法都是安全的。但是在Windows下,一是没有现成可用的信号系统,二是其终止线程的函数相当粗暴会产生一系列后遗症,因此Windows下的线程终止还是比较麻烦的。
使用线程终止函数TerminateThread(不推荐):
Windows提供了一个线程终止函数TerminateThread,但是这个函数有如下缺点,而且这些缺点很多都是让人无法忍受的:
- (!)被终止的线程没有机会清理自己,也不会抛出异常,这可能造成死锁 和 程序崩溃;
- (!)目标线程的堆栈无法被释放,如果程序没有退出的话,那么这个线程可能会造成内存泄漏;
- (!)目标线程如果动态加载了动态库,那么这些动态库也无法被卸载掉,这将造成内存泄漏;
- (!)如果线程在锁住了critical section的时候被终结,那么这个critical section永远无法被释放,那么其他试图获得critical seciton的线程将永远等待下去,这可能造成死锁 和 程序崩溃。
小结:可以看到上述四点,任何一点都会影响程序的稳定性,要么内存泄漏!要么程序死锁!要么程序崩溃!
使用简单的标记判断,然线程清理自己并退出(推荐):
这种方法可以说是返璞归真了,通过在线程中设置判断标记,当达到某个条件时线程进入退出流程。而其标记值的控制则由其他线程来控制。
从方案上来看就知道需要使用线程间同步组件,我们已知的组件有:Mutex、Semaphore、Event、Interlocked、Critical Section。
那么使用哪种组件呢?
Mutex:互斥量,核心对象,锁住Mutex的线程被终止时,其他线程调用WaitForSingleObject会立刻得到应答。
Semaphore:信号量,核心对象,一般用在非互斥场景的同步。
Event:事件,核心对象,使用灵活多变,有异步属性,发生的event不会排队,存在一种死锁场景。
Interlocked:内部计数锁,核心对象,专用作计数对比使用,保证计数和对比数值的原子性,只能用作数值场景。
Critical Section:关键代码段,非核心对象,存在于用户态内存中,效率要比其他任何核心对象都要高很多,但是如果某个锁住 关键代码段的线程被销毁,那么其他所有等待此关键代码段的线程都将永远等待下去,极易形成死锁。
经过筛选和比较,Mutex、Event、Interlocked这三者都是合适的选择。
注意:这里切忌使用Critical Section,因为线程的终止场景正好和Critical Section的缺点场景 “惺惺相惜” ,因此如果代码控制不好极易形成死锁 和 崩溃。