/**
* SharedMutex.h
* @Author Tu Yongce
* @Created 2008-11-17
* @Modified 2008-11-17
* @Version 0.1
*/
#ifndef SHARED_MUTEX_H_INCLUDED
#define SHARED_MUTEX_H_INCLUDED
#ifndef _WIN32
#error "works only on Windows"
#endif
#include <windows.h>
#include "Noncopyable.h"
// 可共享的互斥量
class SharedMutex
: private Noncopyable
{
private:
HANDLE m_mutex;
HANDLE m_sharedEvent;
HANDLE m_exclusiveEvent;
volatile int m_sharedNum;
volatile int m_exclusiveNum;
volatile int m_lockType;
static const int LOCK_NONE = 0;
static const int LOCK_SHARED = 1;
static const int LOCK_EXCLUSIVE = 2;
public:
SharedMutex();
~SharedMutex();
// 获取共享访问权
bool AcquireShared(DWORD waitTime = INFINITE);
// 释放共享访问权
void ReleaseShared();
// 获取独占访问权
bool AcquireExclusive(DWORD waitTime = INFINITE);
// 释放独占访问权
void ReleaseExclusive();
};
#endif // SHARED_MUTEX_H_INCLUDED
/**
* SharedMutex.cpp
* @Author Tu Yongce
* @Created 2008-11-17
* @Modified 2008-11-17
* @Version 0.1
*/
#include "SharedMutex.h"
#include <cassert>
SharedMutex::SharedMutex(): m_sharedNum(0), m_exclusiveNum(0), m_lockType(LOCK_NONE)
{
// 创建用于保护内部数据的互斥量
m_mutex = ::CreateMutex(NULL, FALSE, NULL);
// 创建用于同步共享访问线程的事件(手动事件)
m_sharedEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
// 创建用于同步独占访问线程的事件(自动事件)
m_exclusiveEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);
}
SharedMutex::~SharedMutex()
{
::CloseHandle(m_mutex);
::CloseHandle(m_sharedEvent);
::CloseHandle(m_exclusiveEvent);
}
// 获取共享访问权
bool SharedMutex::AcquireShared(DWORD waitTime)
{
::WaitForSingleObject(m_mutex, INFINITE);
++m_sharedNum;
if (m_lockType == LOCK_EXCLUSIVE) {
DWORD retCode = ::SignalObjectAndWait(m_mutex, m_sharedEvent, waitTime, FALSE);
if (retCode == WAIT_OBJECT_0) {
return true;
} else {
if (retCode == WAIT_TIMEOUT)
::SetLastError(WAIT_TIMEOUT);
return false;
}
}
m_lockType = LOCK_SHARED;
::ReleaseMutex(m_mutex);
return true;
}
// 释放共享访问权
void SharedMutex::ReleaseShared()
{
assert(m_lockType == LOCK_SHARED);
::WaitForSingleObject(m_mutex, INFINITE);
--m_sharedNum;
if (m_sharedNum == 0) {
if (m_exclusiveNum > 0) {
// 唤醒一个独占访问线程
m_lockType = LOCK_EXCLUSIVE;
::SetEvent(m_exclusiveEvent);
} else {
// 没有等待线程
m_lockType = LOCK_NONE;
}
}
::ReleaseMutex(m_mutex);
}
// 获取独占访问权
bool SharedMutex::AcquireExclusive(DWORD waitTime)
{
::WaitForSingleObject(m_mutex, INFINITE);
++m_exclusiveNum;
if (m_lockType != LOCK_NONE) {
DWORD retCode = ::SignalObjectAndWait(m_mutex, m_exclusiveEvent, waitTime, FALSE);
if (retCode == WAIT_OBJECT_0) {
return true;
} else {
if (retCode == WAIT_TIMEOUT)
::SetLastError(WAIT_TIMEOUT);
return false;
}
}
m_lockType = LOCK_EXCLUSIVE;
::ReleaseMutex(m_mutex);
return true;
}
// 释放独占访问权
void SharedMutex::ReleaseExclusive()
{
assert(m_lockType == LOCK_EXCLUSIVE);
::WaitForSingleObject(m_mutex, INFINITE);
--m_exclusiveNum;
// 独占访问线程优先
if (m_exclusiveNum > 0) {
// 唤醒一个独占访问线程
::SetEvent(m_exclusiveEvent);
} else if (m_sharedNum > 0) {
// 唤醒当前所有共享访问线程
m_lockType = LOCK_SHARED;
::PulseEvent(m_sharedEvent);
} else {
// 没有等待线程
m_lockType = LOCK_NONE;
}
::ReleaseMutex(m_mutex);
}
/**
* SharedMutex_example.cpp
* @Author Tu Yongce
* @Created 2008-11-17
* @Modified 2008-11-17
* @Version 0.1
*/
#include <process.h>
#include <iostream>
#include "SharedMutex.h"
using namespace std;
SharedMutex g_mutex;
const int LOOP_NUM = 2000;
volatile __int64 g_data = 0;
CRITICAL_SECTION g_cs;
unsigned WINAPI ReaderThread(void *pParam)
{
int id = (int)pParam;
::EnterCriticalSection(&g_cs);
cout << "Reader [" << id << "] start" << endl;
::LeaveCriticalSection(&g_cs);
__int64 max = 0;
__int64 min = 0;
for (int i = 0; i < LOOP_NUM; ++i) {
g_mutex.AcquireShared();
__int64 data = g_data;
if (data > max)
max = data;
if (data < min)
min = data;
g_mutex.ReleaseShared();
Sleep(1);
}
::EnterCriticalSection(&g_cs);
cout << "Reader [" << id << "] quit, max = " << max << ", min = " << min << endl;
::LeaveCriticalSection(&g_cs);
return 0;
}
unsigned WINAPI WriterThread1(void *pParam)
{
int id = (int)pParam;
::EnterCriticalSection(&g_cs);
cout << "Writer1 [" << id << "] start" << endl;
::LeaveCriticalSection(&g_cs);
for (int i = 0; i < LOOP_NUM; ++i) {
g_mutex.AcquireExclusive();
g_data = g_data + i;
g_mutex.ReleaseExclusive();
Sleep(1);
}
::EnterCriticalSection(&g_cs);
cout << "Writer1 [" << id << "] quit" << endl;
::LeaveCriticalSection(&g_cs);
return 0;
}
unsigned WINAPI WriterThread2(void *pParam)
{
int id = (int)pParam;
::EnterCriticalSection(&g_cs);
cout << "Writer2 [" << id << "] start" << endl;
::LeaveCriticalSection(&g_cs);
for (int i = 0; i < LOOP_NUM; ++i) {
g_mutex.AcquireExclusive();
g_data = g_data - i;
g_mutex.ReleaseExclusive();
Sleep(1);
}
::EnterCriticalSection(&g_cs);
cout << "Writer2 [" << id << "] quit" << endl;
::LeaveCriticalSection(&g_cs);
return 0;
}
int main()
{
::InitializeCriticalSection(&g_cs);
// 创建读写工作线程(创建时挂起工作线程)
HANDLE readers[20];
for (int i = 0; i < _countof(readers); ++i) {
readers[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThread, (void*)i,
CREATE_SUSPENDED, NULL);
}
HANDLE writers1[5];
for (int i = 0; i < _countof(writers1); ++i) {
writers1[i] = (HANDLE)_beginthreadex(NULL, 0, WriterThread1, (void*)i,
CREATE_SUSPENDED, NULL);
}
HANDLE writers2[5];
for (int i = 0; i < _countof(writers2); ++i) {
writers2[i] = (HANDLE)_beginthreadex(NULL, 0, WriterThread2, (void*)i,
CREATE_SUSPENDED, NULL);
}
// 恢复工作线程
for (int i = 0; i < _countof(readers); ++i) {
ResumeThread(readers[i]);
}
for (int i = 0; i < _countof(writers1); ++i) {
ResumeThread(writers1[i]);
}
for (int i = 0; i < _countof(writers2); ++i) {
ResumeThread(writers2[i]);
}
// 等待工作线程结束
WaitForMultipleObjects(_countof(readers), readers, TRUE, INFINITE);
WaitForMultipleObjects(_countof(writers1), writers1, TRUE, INFINITE);
WaitForMultipleObjects(_countof(writers2), writers2, TRUE, INFINITE);
// 释放内核对象句柄
for (int i = 0; i < _countof(readers); ++i) {
CloseHandle(readers[i]);
}
for (int i = 0; i < _countof(writers1); ++i) {
CloseHandle(writers1[i]);
}
for (int i = 0; i < _countof(writers2); ++i) {
CloseHandle(writers2[i]);
}
::DeleteCriticalSection(&g_cs);
cout << ">> Expected data value is " << 0 << ", and the real value is " << g_data << endl;
return 0;
}