Win32线程——等待另一个线程结束
2016-12-14 21:14
204 查看
《Win32多线程程序设计》–Jim Beveridge & Robert Wiener
“等待某个什么东西”是线程常常需要做的事。等待是线程的“必要之恶”。
如果你没有等待线程结束就莽撞地结束程序,线程会被系统强制结束掉——在它完成它的工作之前。
由于让线程停工是操作系统的责任,很合理地我们会认为操作系统也有责任让其他线程知道某个线程停工了。
可使用的核心对象有两种状态:激发与未激发。WaitForSingleObject() 会在目标物变成激发状态时返回。
(范例:保持线程池中始终有3个线程在运行)
结果:
GetMessage() 有点像是特殊版本的 WaitForSingleObject(),它等待消息而
不是核心对象。一旦你调用 GetMessage() ,除非有一个消息真正进入你的消息
队列( message queue )之中,否则它不会返回。
如果你在主线程中正使用 WaitForSingleO bject()或 WaitForMultipleObjects()等待某个对象被激发,你根本没有办法回到主消息循环中去。
为了解决这个问题,主消息循环必须修改,使它得以同时等待消息或是核心对象被激发。你必须使用一个 MsgWaitForMultipleObjects() 函数。这个函数非常类似WaitForMultipleObjects(),但它会在“对象被激发”或“消息到达队列”时被唤醒而返回。MsgWaitForMultipleObjects() 多接受一个参数,允许指定哪些消息是观察对象。
“等待某个什么东西”是线程常常需要做的事。等待是线程的“必要之恶”。
如果你没有等待线程结束就莽撞地结束程序,线程会被系统强制结束掉——在它完成它的工作之前。
由于让线程停工是操作系统的责任,很合理地我们会认为操作系统也有责任让其他线程知道某个线程停工了。
Sleep()
这个函数要求操作系统中止线程动作,直到渡过某个指定时间之后才恢复。#include <stdio.h> #include <Windows.h> DWORD WINAPI Thread(void *arg) { // doing something return 0; } int main(void) { HANDLE hThread = CreateThread(NULL, 0, Thread, NULL, 0, NULL); Sleep(?); // 不可能事先知道要等待Thread多久 CloseHandle(hThread); return 0; }
GetExitCodeThread()轮询检查
使用 GetExitCodeThread() 可以决定一个线程是否还在执行。#include <stdio.h> #include <Windows.h> DWORD WINAPI Thread(void *arg) { // doing something return 0; } int main(void) { DWORD exitCode = 0; HANDLE hThread = CreateThread(NULL, 0, Thread, NULL, 0, NULL); while (1) { GetExitCodeThread(hThread, &exitCode); // 严重浪费 CPU 时间 if (STILL_ACTIVE != exitCode) break; } CloseHandle(hThread); return 0; }
WaitForSingleObject()
可看成一个新版的 Sleep() ,它能够在某个线程结束时(而不是某段时间结束时)被调用。可使用的核心对象有两种状态:激发与未激发。WaitForSingleObject() 会在目标物变成激发状态时返回。
对象 | 说明 |
---|---|
Thread(线程) | 当线程结束时,线程对象即被激发。当线程还在进行时,则对象处于未激发状态。 |
Process(进程) | 当进程结束时,进程对象即被激发。当进程还在进行时,则对象处于未激发状态。 |
Event | Event 对象的状态直接受控于应用程序所使用的三个Win32函数:SetEvent()、PulseEvent()、ResetEvent()。CreateEvent()和OpenEvent()都可以传回一个event object handle。Event对象的状态也可以被操作系统设定。 |
Mutex | 如果mutex没有被任何线程拥有,它就是处于激发状态。一旦一个等待mutex的函数返回了,mutex也就自动重置为未激发状态。 |
Semaphore | Semaphore有点像mutex,但它有个计数器,可以约束其拥有者(线程)的个数。当计数器内容大于 0时,semaphore处于激发状态,当计数器内容等于0时,semaphore处于未激发状态。 |
#include <stdio.h> #include <Windows.h> DWORD WINAPI Thread(void *arg) { // doing something return 0; } int main(void) { HANDLE hThread = CreateThread(NULL, 0, Thread, NULL, 0, NULL); WaitForSingleObject(hThread, INFINITE); // 等待,直到线程被激发 CloseHandle(hThread); return 0; }
WaitForMultipleObjects()
允许你在同一时间等待一个以上的对象。你必须将一个由 handles 组成的数组交给此函数,并指定要等待其中一个对象或是全部的对象。(范例:保持线程池中始终有3个线程在运行)
#include <assert.h> #include <stdio.h> #include <stdlib.h> #include <windows.h> #define POOL_SIZE 3 // 线程池大小 #define TASK_NUM 6 DWORD WINAPI ThreadFunc(LPVOID n) { srand(GetTickCount()); Sleep(rand()%5000+500); printf("%d over\n", n); return ((DWORD)n); } int main(void){ HANDLE hThrds[POOL_SIZE]; int pIdx = 0, tIdx; DWORD rc; for (tIdx = 1; tIdx <= TASK_NUM; tIdx++) { if (tIdx > POOL_SIZE) { rc = WaitForMultipleObjects(POOL_SIZE, hThrds, FALSE, INFINITE); // 等待hThrds数组中任意一个变为激发状态,返回其索引 pIdx = rc - WAIT_OBJECT_0; assert(pIdx >= 0 && pIdx < POOL_SIZE); printf("%d terminated\n", pIdx); CloseHandle(hThrds[pIdx]); } hThrds[pIdx++] = CreateThread(NULL, 0, ThreadFunc, (LPVOID)pIdx, 0, NULL); printf("Thread #%d launched (pIdx %d)\n", tIdx, pIdx); } WaitForMultipleObjects(POOL_SIZE, hThrds, TRUE, INFINITE); // 等待hThrds数组中所有线程变为激发状态 for (pIdx = 0; pIdx < POOL_SIZE; pIdx++) CloseHandle(hThrds[pIdx]); return EXIT_SUCCESS; }
结果:
GUI 程序中等待
Windows 程序中的“主消息循环”看起来像这个样子:while (GetMessage(&msg, NULL, 0, 0,)) { TranslateMessage(&msg); DispatchMessage(&msg); }
GetMessage() 有点像是特殊版本的 WaitForSingleObject(),它等待消息而
不是核心对象。一旦你调用 GetMessage() ,除非有一个消息真正进入你的消息
队列( message queue )之中,否则它不会返回。
如果你在主线程中正使用 WaitForSingleO bject()或 WaitForMultipleObjects()等待某个对象被激发,你根本没有办法回到主消息循环中去。
为了解决这个问题,主消息循环必须修改,使它得以同时等待消息或是核心对象被激发。你必须使用一个 MsgWaitForMultipleObjects() 函数。这个函数非常类似WaitForMultipleObjects(),但它会在“对象被激发”或“消息到达队列”时被唤醒而返回。MsgWaitForMultipleObjects() 多接受一个参数,允许指定哪些消息是观察对象。
相关文章推荐
- 线程:Java主线程等待子线程结束
- Windows和Linux上分别怎样实现等待某个线程结束?---用WaitForSingleObject和pthread_join
- c++11线程管理,RAII方式等待异常环境下线程结束
- Java Thread.join()详解--父线程等待子线程结束后再结束
- CountDownLatch实现主线程等待所有子线程运行结束后再继续执行的实现
- 线程创建,属性设置与获得,等待线程结束,线程中fork,以及执行exec()
- linux shell wait process finished,等待线程执行结束
- java并发-主线程等待子线程结束
- 线程结束等待与线程优先级
- Java多线程协作CountDownLatch,主线程等待子线程结束
- java中对线程的实现 等待多个子线程结束 多个子线程运行中进行同步
- 多线程之join()方法---(Thread提供的让一个线程等待另一个线程完成的方法)
- java中一个线程等待另一个线程执行完后再执行
- 利用ThreadGroup等待所有线程执行结束
- 1.写多进程,一个父进程,两个子进程,一个运行ls –l, 另一个暂停5s,父进程先阻塞等待第一个子进程的结束,然后用非阻塞等另一个进程退出,收集到第二个子进程结束的信息,父进程就返回。
- iOS 中使用GCD怎么让两个线程执行完结束后再去执行另一个线程
- Win32线程——在某个线程内终止另一个正在运行的线程(1)
- 主线程等待子线程执行结束后再执行的实现方式
- 以事件通知线程结束,并等待线程安全退出
- WIN32多线程二 用WaitXXX函数等待线程结束