一、互斥对象
互斥对象属于系统内核对象,它能够使线程拥有对某个资源的绝对访问权。互斥对象主要包含使用数量、线程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这一张票的可能性;