一、互斥对象
互斥对象属于系统内核对象,它能够使线程拥有对某个资源的绝对访问权。互斥对象主要包含使用数量、线程ID、递归计数器等。线程ID表示当前拥有互斥对象的线程,递归计数器表示线程拥有互斥对象的次数。
1、当互斥对象的线程ID为0时,表示互斥对象不被任何线程所拥有,此时系统会发出该互斥对象的通知信号,等待该互斥对象的其他线程中的某一个线程会拥有该互斥对象,同时,互斥对象的线程ID为当前拥有该互斥对象的线程的线程ID。
2、当互斥对象的线程ID不为0时,表示当前有线程拥有该互斥对象。系统不会发出互斥对象的通知信号。其他等待互斥对象的线程继续等待,直到拥有改互斥对象的线程释放互斥对象的拥有权。
二、创建互斥对象
CreateMutex函数创建一个互斥对象,成功返回该互斥对象的句柄,失败返回NULL。
HANDLE WINAPI CreateMutex( __in LPSECURITY_ATTRIBUTES lpMutexAttributes,//互斥对象的安全属性 __in BOOL bInitialOwner,//互斥对象的初始状态;TRUE表示互斥对象的线程ID为当前调度线程的线程ID,当前创建互斥对象的线程具有他的拥有权,互斥对象的递归计数器为1 __in LPCTSTR lpName//互斥对象的名称,NULL表示创建一个匿名的互斥对象 );
当某一个线程拥有互斥对象所有权后,就可以独占系统中受保护的资源;不再需要资源的时候,可以调用ReleaseMutex函数释放互斥对象的所有权;ReleaseMutex函数每调用一次,递归计数器减1;直到减到0时才释放互斥对象,互斥对象才变为通知状态。
BOOL WINAPI ReleaseMutex( __in HANDLE hMutex );等待互斥对象WaitForSingleObject函数
DWORD WINAPI WaitForSingleObject( __in HANDLE hHandle,//等待内核对象句柄 __in DWORD dwMilliseconds//等待时间,INFINITE表示无限等待 );
失败返回WAIT_FAILED;
三、卖票系统试题
有三个卖票的位置;卖100张票;
CMutex.h文件
#ifndef _CMUTEX_H__ #define _CMUTEX_H__ class CMutex { public: CMutex(); ~CMutex(); void StartThread(); static DWORD __stdcall ThreadFun1(LPVOID lParam);//卖家1 static DWORD __stdcall ThreadFun2(LPVOID lParam);//卖家2 static DWORD __stdcall ThreadFun3(LPVOID lParam);//卖家3 private: HANDLE m_hThread1; HANDLE m_hThread2; HANDLE m_hThread3; HANDLE hMutex;//互斥对象 static int nTickets;//票的总数 }; #endif
#include "stdafx.h" #include "CMutex.h" int CMutex::nTickets = 100; CMutex::CMutex() { hMutex = CreateMutex(NULL, FALSE, L"mutex"); } CMutex::~CMutex() { if (NULL != hMutex) { CloseHandle(hMutex); hMutex = NULL; } if (NULL != m_hThread1) { CloseHandle(m_hThread1); m_hThread1 = NULL; } if (NULL != m_hThread2) { CloseHandle(m_hThread2); m_hThread2 = NULL; } if (NULL != m_hThread3) { CloseHandle(m_hThread3); m_hThread3 = NULL; } } DWORD __stdcall CMutex::ThreadFun1(LPVOID lParam) { DWORD dRet = TRUE; CMutex * pThis = (CMutex*)lParam; while (1) { WaitForSingleObject(pThis->hMutex, INFINITE); if (pThis->nTickets < 1) { break; } cout<<"ThreadFun1 卖出票:"<<pThis->nTickets--<<endl; ReleaseMutex(pThis->hMutex); } return dRet; } DWORD __stdcall CMutex::ThreadFun2(LPVOID lParam) { DWORD dRet = TRUE; CMutex * pThis = (CMutex*)lParam; while (1) { WaitForSingleObject(pThis->hMutex, INFINITE); if (pThis->nTickets < 1) { break; } cout<<"ThreadFun2 卖出票:"<<pThis->nTickets--<<endl; ReleaseMutex(pThis->hMutex); } return dRet; } DWORD __stdcall CMutex::ThreadFun3(LPVOID lParam) { DWORD dRet = TRUE; CMutex * pThis = (CMutex*)lParam; while (1) { WaitForSingleObject(pThis->hMutex, INFINITE); if (pThis->nTickets < 1) { break; } cout<<"ThreadFun3 卖出票:"<<pThis->nTickets--<<endl; ReleaseMutex(pThis->hMutex); } return dRet; } void CMutex::StartThread() { m_hThread1 = CreateThread(NULL, 0, &CMutex::ThreadFun1, this, 0, NULL); m_hThread2 = CreateThread(NULL, 0, &CMutex::ThreadFun2, this, 0, NULL); m_hThread3 = CreateThread(NULL, 0, &CMutex::ThreadFun3, this, 0, NULL); }
main.cpp
// Mutex.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "CMutex.h" int _tmain(int argc, _TCHAR* argv[]) { CMutex myMutex; myMutex.StartThread(); Sleep(4000); system("pause"); return 0; }
结果
如果不加互斥对象,将可能出现卖出0这一张票的可能性;