C++ 线程同步互斥量Mutex

一、互斥对象

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


猜你喜欢

转载自blog.csdn.net/qwerdf10010/article/details/79662603