接上篇....
先来看看代码,如下:
MultiThread4.cpp
#include <windows.h>
#include <iostream>
using namespace std ;
DWORD WINAPI ThreadProc1(LPVOID lpParameter) ;
DWORD WINAPI ThreadProc2(LPVOID lpParameter) ;
int index ;
int tickets = 100 ;
HANDLE hMutex ; // 声明一个全局的互斥对象句柄
int main()
{
HANDLE hThread1 ;
HANDLE hThread2 ;
hThread1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL) ;
hThread2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL) ;
CloseHandle(hThread1) ; // 关闭线程内核对象句柄, 并没有阻止新建线程的结束, 但是将线程内核对象的引用计数减1,
CloseHandle(hThread2) ; // 当新建线程执行完成后, 引用计数也会减1。 当引用计数为0时, 系统就会释放线程内核对象
hMutex = CreateMutex(NULL, TRUE, NULL) ; // 创建一个属于当前线程的匿名互斥对象
WaitForSingleObject(hMutex, INFINITE) ;
ReleaseMutex(hMutex) ; // 释放当前线程对互斥对象的所有权
ReleaseMutex(hMutex) ;
Sleep(4000) ;
return 0 ;
}
DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
WaitForSingleObject(hMutex, INFINITE) ;
cout << "thread one is running..." << endl ;
return 0 ;
}
DWORD WINAPI ThreadProc2(LPVOID lpParameter)
{
WaitForSingleObject(hMutex, INFINITE) ;
cout << "thread two is running..." << endl ;
return 0 ;
}
在上面的代码中,线程一(ThreadProc1)请求到了互斥对象(hMutex),在工作完成后,我们并没有释放线程一对互斥对象的所有权,我们来看看线程二(ThreadProc2)是否
被执行, 输出结果如下:
我们可以看到,线程二也是可以被执行的,这是为什么呢?请看下面的分析:
分析:
当一个线程得到一个互斥对象后,如果在线程运行完之前,没有去释放互斥对象,那么操作系统一旦发现这个线程已经终止,那么操作系统自动将这个线程所拥有的互斥
对象的线程ID设置为0,然后将其计数器也归为0,这样线程二(ThreadProc2)中,就可以使用WaitForSingleObject()函数请求到对互斥对象的所有权,那么我们是怎么知道
他请求到的互斥对象是正常的请求到还是当线程一终止时请求得到的互斥对象呢?可以通过WaitForSingleObject()函数的返回值来判断,其返回值类型如下:
如果我们所请求的互斥对象变为信号态是因为线程异常终止或者是终止之前没有调用ReleaseMutex()函数而结束的,那么WaitForSingleObject()函数的返回值就是
WAIT_ABANDONED,那么我们就可以通过这个返回值来确定线程二是如何请求到该互斥对象的所有权;同样的根据返回值WAIT_ABANDONED我们知道线程一不是通
过调用ReleaseMutex()函数终止的,可能是线程执行完成后终止,也可能使线程一异常终止,那么对于线程一的异常终止,就表示线程一中的工作并没有正常的完成,
所以,我们在处理线程二中的代码时,可以在WaitForSingleObject()函数返回WAIT_ABANDONED时进行一些适当的处理,从而保证程序的正常运行。