许多应用程序存在一个基本的同步问题,这个问题称为单个写入程序/多个阅读程序环境。
该问题涉及到试图访问共享资源的任意数量的线程。这些线程中,有些线程(写入程序)需要
修改数据的内容,而有些线程(阅读程序)则需要读取数据。由于下面4个原则,它们之间的
同步是必要的:
1) 当一个线程正在写入数据时,其他任何线程不能写入数据。
2) 当一个线程正在写入数据时,其他任何线程不能读取数据。
3) 当一个线程正在读取数据时,其他任何线程不能写入数据。
4) 当一个线程正在读取数据时,其他线程也能够读取数据。
代码如下:
--------------------------------------------
SWMRG.h
#pragma once
#include <Windows.h>
class CSWMRG
{
public:
CSWMRG(void);
public:
~CSWMRG(void);
void WaitToRead(); // Call this to gain shared read access
void WaitToWrite(); // Call this to gain exclusive write access
void Done(); // Call this when done accessing the resource
public:
CRITICAL_SECTION m_cs;
int m_nActive;
int m_nWaitingReaders;
int m_nWaitingWriters;
HANDLE m_hsemReaders;
HANDLE m_hsemWriters;
};
----------------------------------------------
SWMRG.cpp
#include "SWMRG.h"
CSWMRG::CSWMRG(void)
{
m_nActive = m_nWaitingWriters = m_nWaitingReaders = 0;
InitializeCriticalSection(&m_cs);
m_hsemReaders = CreateSemaphore(NULL, 0, MAXLONG, NULL);
m_hsemWriters = CreateSemaphore(NULL, 0, MAXLONG, NULL);
}
CSWMRG::~CSWMRG(void)
{
m_nActive = m_nWaitingWriters = m_nWaitingReaders = 0;
DeleteCriticalSection(&m_cs);
CloseHandle(m_hsemReaders);
CloseHandle(m_hsemWriters);
}
void CSWMRG::WaitToRead()
{
EnterCriticalSection(&m_cs);
// Are there writers waiting ?
bool bWaitingWrite = (m_nWaitingWriters || m_nActive < 0);
// wait to read
if(bWaitingWrite)
{
m_nWaitingReaders++;
}
else
{
// read the resource
m_nActive++;
}
LeaveCriticalSection(&m_cs);
if(bWaitingWrite)
WaitForSingleObject(m_hsemReaders, INFINITE);
}
void CSWMRG::WaitToWrite()
{
EnterCriticalSection(&m_cs);
// Are there readers waiting ?
bool bWaitingRead = (m_nActive != 0);
if (bWaitingRead)
{
m_nWaitingWriters++;
}
else
{
m_nActive = -1;
}
LeaveCriticalSection(&m_cs);
if(bWaitingRead)
WaitForSingleObject(m_hsemWriters, INFINITE);
}
void CSWMRG::Done()
{
EnterCriticalSection(&m_cs);
if(m_nActive)
{
m_nActive--;
}
else
{
m_nActive++;
}
HANDLE hsem = NULL;
LONG lCount = 1; // Assume only 1 waiter wakes; always true for writers
if (m_nActive == 0)
{
if (m_nWaitingWriters > 0)
{
m_nActive = -1;
m_nWaitingWriters--;
hsem = m_hsemWriters;
}
else if (m_nWaitingReaders > 0)
{
m_nActive = m_nWaitingReaders;
m_nWaitingReaders = 0;
hsem = m_hsemReaders;
lCount = m_nActive;
}
}
LeaveCriticalSection(&m_cs);
if (hsem != NULL)
{
ReleaseSemaphore(hsem, lCount, NULL);
}
}
--------------------------------------------
Test.cpp
#include "SWMRG.h"
#include <tchar.h>
#include <process.h> // for _beginthreadex
#include <BaseTsd.h>
CSWMRG g_swmrg;
unsigned __stdcall Thread(PVOID pvParam)
{
TCHAR sz[50];
//#define PtrToShort( p ) ((short)(LONG_PTR)(p) )
wsprintf(sz, TEXT("SWMRG Test: Thread %d"), PtrToShort(pvParam));
int n = MessageBox(NULL, TEXT("YES: Attempt to read/nNO: Attempt to write"), sz, MB_YESNO);
// Attempt to read or write
if (n == IDYES)
g_swmrg.WaitToRead();
else
g_swmrg.WaitToWrite();
MessageBox(NULL, (n == IDYES) ? TEXT("OK stops READING") : TEXT("OK stops WRITING"), sz, MB_OK);
// Stop reading/writing
g_swmrg.Done();
return 0;
}
int WINAPI _tWinMain(HINSTANCE hinstExe, HINSTANCE, PTSTR pszCmdLine, int)
{
HANDLE hThread[5];
int nThread = 0;
for (nThread = 0; nThread < 5; nThread++)
{
DWORD dwThreadId = 0;
hThread[nThread] = (HANDLE)_beginthreadex(NULL, 0, Thread, (void *)&nThread, 0, (unsigned *)&dwThreadId);
}
// Wait for all the threads to exit
WaitForMultipleObjects(nThread, hThread, true, INFINITE);
while (nThread--)
CloseHandle(hThread[nThread]);
return 0;
}