您的位置:首页 > 其它

《Win32多线程程序设计》之线程终止

2017-08-23 22:36 155 查看
本文讨论如何在某个线程内终止另一个正在运行的线程或者在一个线程中控制其他线程类似问题

方法一:利用 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()来等待其变为有信号
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  多线程