《Win32多线程程序设计》之线程终止
2017-08-23 22:36
155 查看
本文讨论如何在某个线程内终止另一个正在运行的线程或者在一个线程中控制其他线程类似问题
方法一:利用 TerminateThread() 放弃一个线程
“TerminateThread() 是一个危险的函数, 应该在最不得已的情况下才使用”。
缺点:
- 目标线程结束前无法释放堆栈,可能造成内存泄漏
- 如果线程在一个critical section中,则该critical section也将永远处于锁定,死锁了。
方法二:跨越线程,丢出异常情况(Exceptions)
“模拟丢出一个异常情况到另一个线程”,但Win32 API 中没有什么标准方法可以把一个异常情况丢到另一个线程中。
技术之一是利用 debugging API 写一个不合法的指令到目标线程的目前地址上。另一种做法是改变一个常用的指针,使它指向一个不合法地址,因而强迫程序代码产生一个异常情况。这两种做法都有缺点,但当你别无它途时,不妨一试。【待试一试】
方法三:设立一个标记
优点:保证目标线程结束之前安全而一致的状态。
缺点:线程需要时时检查标记值,可使用一个手动重置的event对象,检查其状态或者等待它。
Event方法具体实现:
产生两个线程,目标线程周期性地检查一个 event 对象(全局变量),以决定要不要结束自己。
如下摘录的例子,计算PI, 很有意思。
这个例子并不一定需要 event 对象,但如果我们使用它, worker 线程就能够在必要时候等待之。例如 worker 线程可以利用 event 对象来等待一个 Internet
socket 的连接成功,或是等待用户发出离开的请求。我们只要把上述 worker线程中的 WaitForSingleObject() 改为 WaitForMultipleObjects() 即可。
此处,在重申一遍CreateEvent的用法
事件处于开状态,为有信号;关状态,为无信号。
bManualReset:
TRUE表示手动复位,Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复无信号。
FALSE表示自动复位,Event被设置为有信号,则当有一个wait到它的Thread时, 该Event就会自动复位变成无信号,如果想在每次调用WaitForSingleObject 后让WINDOWS为您自动地把事件地状态恢复为”无信号”状态,必须把该参数设为FALSE,否则,必须每次调用ResetEvent函数来清除事件的信号。
bInitialState:
初始状态。TRUE 有信号,FALSE无信号。
一个Event被创建以后,可以:
用OpenEvent()API来获得它的Handle,
用CloseHandle()来关闭它,
用SetEvent()或PulseEvent()来设置它使其有信号,
用ResetEvent()来使其无信号,
用WaitForSingleObject()或WaitForMultipleObjects()来等待其变为有信号。
方法一:利用 TerminateThread() 放弃一个线程
“TerminateThread() 是一个危险的函数, 应该在最不得已的情况下才使用”。
缺点:
- 目标线程结束前无法释放堆栈,可能造成内存泄漏
- 如果线程在一个critical section中,则该critical section也将永远处于锁定,死锁了。
方法二:跨越线程,丢出异常情况(Exceptions)
“模拟丢出一个异常情况到另一个线程”,但Win32 API 中没有什么标准方法可以把一个异常情况丢到另一个线程中。
技术之一是利用 debugging API 写一个不合法的指令到目标线程的目前地址上。另一种做法是改变一个常用的指针,使它指向一个不合法地址,因而强迫程序代码产生一个异常情况。这两种做法都有缺点,但当你别无它途时,不妨一试。【待试一试】
方法三:设立一个标记
优点:保证目标线程结束之前安全而一致的状态。
缺点:线程需要时时检查标记值,可使用一个手动重置的event对象,检查其状态或者等待它。
Event方法具体实现:
产生两个线程,目标线程周期性地检查一个 event 对象(全局变量),以决定要不要结束自己。
如下摘录的例子,计算PI, 很有意思。
#include <stdio.h> #include <stdlib.h> #include <windows.h> #include <time.h> DWORD WINAPI ThreadFunc(LPVOID); HANDLE hRequestExitEvent = FALSE; int main() { HANDLE hThreads[2]; DWORD dwThreadId; DWORD dwExitCode = 0; int i; hRequestExitEvent = CreateEvent( NULL, TRUE, FALSE, NULL); for (i = 0; i<2; i++) hThreads[i] = CreateThread(NULL, 0, ThreadFunc, (LPVOID)i, 0, &dwThreadId ); // Wait around for awhile, make // sure the thread is running. Sleep(10000); SetEvent(hRequestExitEvent); WaitForMultipleObjects(2, hThreads, TRUE, INFINITE); for (i = 0; i<2; i++) CloseHandle(hThreads[i]); return EXIT_SUCCESS; } DWORD WINAPI ThreadFunc(LPVOID p) { int i; int inside = 0; /* Seed the random-number generator */ srand((unsigned)time(NULL)); for (i = 0; i<1000000; i++) { double x = (double)(rand()) / RAND_MAX; double y = (double)(rand()) / RAND_MAX; if ((x*x + y*y) <= 1.0) inside++; if (WaitForSingleObject(hRequestExitEvent, 0) != WAIT_TIMEOUT) { printf("Received request to terminate\n"); return (DWORD)-1; } } printf("PI = %.4g inside = %d, i = %d\n", (double)inside / i * 4, inside, i ); return 0; }
这个例子并不一定需要 event 对象,但如果我们使用它, worker 线程就能够在必要时候等待之。例如 worker 线程可以利用 event 对象来等待一个 Internet
socket 的连接成功,或是等待用户发出离开的请求。我们只要把上述 worker线程中的 WaitForSingleObject() 改为 WaitForMultipleObjects() 即可。
此处,在重申一遍CreateEvent的用法
事件处于开状态,为有信号;关状态,为无信号。
HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // SD BOOL bManualReset, // reset type BOOL bInitialState, // initial state LPCTSTR lpName // object name );
bManualReset:
TRUE表示手动复位,Event被设置为有信号,则它一直会等到ResetEvent()API被调用时才会恢复无信号。
FALSE表示自动复位,Event被设置为有信号,则当有一个wait到它的Thread时, 该Event就会自动复位变成无信号,如果想在每次调用WaitForSingleObject 后让WINDOWS为您自动地把事件地状态恢复为”无信号”状态,必须把该参数设为FALSE,否则,必须每次调用ResetEvent函数来清除事件的信号。
bInitialState:
初始状态。TRUE 有信号,FALSE无信号。
一个Event被创建以后,可以:
用OpenEvent()API来获得它的Handle,
用CloseHandle()来关闭它,
用SetEvent()或PulseEvent()来设置它使其有信号,
用ResetEvent()来使其无信号,
用WaitForSingleObject()或WaitForMultipleObjects()来等待其变为有信号。
相关文章推荐
- 《Win32多线程程序设计》(10)---如何终止一个线程
- 看此文 学会利用 CEvent实现从主线程 终止 线程
- Java并发 正确终止与恢复线程
- 线程概述,优先级,睡眠,创建及终止(VC_Win32)
- PL/SQL 查询session杀不掉,强制终止线程的解决方法
- 终止线程两个函数:ExitThread 和 TerminateThread
- 怎么样终止一个线程呢?
- Android之线程终止
- Android终止线程的方法
- 终止线程的方法
- 两个按钮分别是线程的打开和终止
- Qt学习之如何启动和终止一个线程
- Python多线程之线程创建和终止
- 精通Java多线程学习(七)终止线程、守护线程
- DELPHI 线程的终止和退出
- 深入浅出Win32多线程程序设计(二):线程控制
- Java 优雅的终止线程
- 如何终止java线程
- 终止线程的三种方法
- 线程挂起恢复与终止