進程、線程同步互斥學習 —— 互斥器

關於互斥器,先看MSDN介紹:

Mutex Objects
A mutex object is a synchronization object whose state is set to signaled when it is not owned by any thread, and nonsignaled when it is owned. Only one thread at a time can own a mutex object, whose name comes from the fact that it is useful in coordinating mutually exclusive access to a shared resource. 

即:Mutex可以被某一個線程在某一時刻被單獨擁有,Mutex從有信號轉變成無信號。


初始化

A thread uses the CreateMutex orCreateMutexEx function to create a mutex object. The creating thread can request immediate ownership of the mutex object and can also specify a name for the mutex object. It can also create an unnamed mutex. 

HANDLE WINAPI CreateMutex(
  __in_opt  LPSECURITY_ATTRIBUTES lpMutexAttributes,
  __in      BOOL bInitialOwner,
  __in_opt  LPCTSTR lpName
);
HANDLE WINAPI CreateMutexEx(
  __in_opt  LPSECURITY_ATTRIBUTES lpMutexAttributes,
  __in_opt  LPCTSTR lpName,
  __in      DWORD dwFlags,
  __in      DWORD dwDesiredAccess
);

lpMutexAttributes SECURITY_ATTRIBUTES  安全屬性。
bInitialOwner 如創建進程希望立即擁有互斥體,則設爲TRUE,一個互斥體同時只能由一個線程擁有。
lpName String 指定互斥體對象的名字。

dwFlags  0或者CREATE_MUTEX_INITIAL_OWNER(0x00000001)

dwDesiredAccess  訪問權限

當我們在做某倆進程互斥的時候,可用OpenMutex打開已存在的Mutex

HANDLE WINAPI OpenMutex(
  __in  DWORD dwDesiredAccess,
  __in  BOOL bInheritHandle,
  __in  LPCTSTR lpName
);


wait操作

Any thread with a handle to a mutex object can use one of thewait functions to request ownership of the mutex object. 

我們可以用wait functions對Mutex進行等待操作

比如 SignalObjectAndWaitWaitForSingleObjectWaitForSingleObjectEx當某個線程得到Mutex時,此Mutex變爲無信號狀態。


signal操作

If the mutex object is owned by another thread, the wait function blocks the requesting thread until the owning thread releases the mutex object using theReleaseMutex function.

BOOL WINAPI ReleaseMutex(
  __in  HANDLE hMutex
);
即:釋放MutexMutex變爲有信號狀態。


測試代碼:

Mutex.h

#pragma once
#include <windows.h>

class ILock
{
public:
	virtual void lock() = 0;
	virtual void unlock() = 0;
};

class _CMutex : public ILock
{
public:
	_CMutex();
	~_CMutex();

	virtual void lock();
	virtual void unlock();
private:
	HANDLE m_hMutex;
};

class CLock
{
public:
	CLock(ILock&);
	~CLock();
private:
	ILock& m_lock;
};

Mutex.cpp

#include "stdafx.h"
#include "Mutex.h"
#include <assert.h>

_CMutex::_CMutex()
{
	m_hMutex = ::CreateMutex(NULL, FALSE, NULL);
	assert(m_hMutex);
}

_CMutex::~_CMutex()
{
	::CloseHandle(m_hMutex);
}

void _CMutex::lock()
{
	WaitForSingleObject(m_hMutex, INFINITE);
}

void _CMutex::unlock()
{
	::ReleaseMutex(m_hMutex);
}


CLock::CLock(ILock& locker) : m_lock(locker)
{
	m_lock.lock();
}

CLock::~CLock()
{
	m_lock.unlock();
}
test.cpp
// Mutex_test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <process.h>
#include "Mutex.h"
#define THREADCOUNT 10
_CMutex g_mutex;
int nFood = 0;

unsigned int WINAPI EatThread(void *pParam)
{
	int i = (int)pParam;
	int nHasEaten = 0;
	while (true)
	{
		CLock lock(g_mutex);
		if (nFood > 0)
		{
			Sleep(100);
			std::cout << "消費者" << i << "進行消費,已經吃掉(" << ++nHasEaten << "),當前剩餘食物" << --nFood << std::endl;
		}
		else
		{
			break;
		}
	}
	return 0;
}

unsigned int WINAPI ProductThread(void *pParam)
{
	int i = 0;
	while (i < 52)
	{
		std::cout << "生產者進行生產,當前剩餘食物" << ++nFood << std::endl;
		i++;
	}
	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	HANDLE hProductThread;
	HANDLE hEatThread[THREADCOUNT];

	hProductThread = (HANDLE)_beginthreadex(NULL, 0, &ProductThread, (void *)0, 0, 0);
	WaitForSingleObject(hProductThread, INFINITE);

	for (int i = 0; i < THREADCOUNT; i++)
	{
		hEatThread[i] = (HANDLE)_beginthreadex(NULL, 0, &EatThread, (void *)i, 0, 0);
	}
	WaitForMultipleObjects(THREADCOUNT, hEatThread, TRUE, INFINITE);

	::CloseHandle(hProductThread);
	for (int i = 0; i < THREADCOUNT; i++)
	{
		::CloseHandle(hEatThread[i]);
	}

	system("pause");
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章