读可以并发,写是互斥,读写互斥,读写按顺序操作。
Linux上有现成的,但是Windows上貌似没有这样的机制,没办法,自己实现一个。好恶心啊,放在这里,以备后用。
pthread_rwlock.h
#ifndef PTHREAD_RWLOCK_H
#define PTHREAD_RWLOCK_H
#ifdef WIN32
#include "StdAfx.h"
typedef enum
{
RW_READ_LOCK = 0,
RW_WRITE_LOCK
}pthread_rwlock_t_lock_mode;
typedef struct pthread_rwlock_t_node
{
HANDLE hEvent;
pthread_rwlock_t_lock_mode eLockMode;
struct pthread_rwlock_t_node *pNext;
}pthread_rwlock_t_node;
typedef struct pthread_rwlock_t
{
HANDLE hMutex;
pthread_rwlock_t_node *pFirstNode;
}pthread_rwlock_t;
typedef void pthread_rwlockattr_t;
extern int pthread_rwlock_destroy(pthread_rwlock_t *
rwlock);
extern int pthread_rwlock_init(pthread_rwlock_t * rwlock,
const pthread_rwlockattr_t *attr);
extern int pthread_rwlock_rdlock(pthread_rwlock_t *
rwlock);
extern int pthread_rwlock_unlock(pthread_rwlock_t *
rwlock);
extern int pthread_rwlock_wrlock(pthread_rwlock_t *
rwlock);
typedef pthread_rwlock_t RWLockT;
#define RWInitLock(_lockdata_)
(pthread_rwlock_init((_lockdata_), NULL) == 0)
#define RWReadLock(_lockdata_)
(pthread_rwlock_rdlock(_lockdata_) == 0)
#define RWWriteLock(_lockdata_)
(pthread_rwlock_wrlock(_lockdata_) == 0)
#define RWUnlock(_lockdata_)
(pthread_rwlock_unlock(_lockdata_) == 0)
#define RWCloseLock(_lockdata_)
(pthread_rwlock_destroy(_lockdata_) == 0)
#endif
#endif
pthread_rwlock.cpp
#include "StdAfx.h"
#include "pthread_rwlock.h"
#define Assert ASSERT
#ifdef WIN32
int pthread_rwlock_destroy (pthread_rwlock_t *
rwlock)
{
Assert(NULL != rwlock);
if (WAIT_OBJECT_0 !=
WaitForSingleObject(rwlock->hMutex,
INFINITE))
{
return -1;
}
if (NULL != rwlock->pFirstNode)
{
pthread_rwlock_t_node *pLast;
pthread_rwlock_t_node *p;
pLast = rwlock->pFirstNode;
while(NULL != pLast)
{
CloseHandle(pLast->hEvent);
p = pLast->pNext;
free(pLast);
pLast = p;
}
}
CloseHandle(rwlock->hMutex);
return 0;
}
int pthread_rwlock_init (pthread_rwlock_t * rwlock, const
pthread_rwlockattr_t *attr)
{
Assert(NULL != rwlock);
Assert(NULL == attr);
rwlock->pFirstNode = NULL;
rwlock->hMutex = CreateMutex(NULL, false,
NULL);
if (INVALID_HANDLE_VALUE ==
rwlock->hMutex)
return -1;
return 0;
}
int pthread_rwlock_rdlock(pthread_rwlock_t *
rwlock)
{
pthread_rwlock_t_node *p;
pthread_rwlock_t_node *pNew;
bool bCanRunNow = true;
Assert(NULL != rwlock);
if (WAIT_OBJECT_0 !=
WaitForSingleObject(rwlock->hMutex,
INFINITE))
return -1;
pNew =
(pthread_rwlock_t_node*)malloc(sizeof(pthread_rwlock_t_node));
if (NULL == pNew)
{
fprintf(stderr, ("Out of memory\n"));
ReleaseMutex(rwlock->hMutex);
return -1;
}
pNew->eLockMode = RW_READ_LOCK;
pNew->hEvent = CreateEvent(NULL, true, false,
NULL);
pNew->pNext = NULL;
if (INVALID_HANDLE_VALUE == pNew->hEvent)
{
ReleaseMutex(rwlock->hMutex);
free(pNew);
return -1;
}
if (NULL == rwlock->pFirstNode)
{
rwlock->pFirstNode = pNew;
}
else
{
p = rwlock->pFirstNode;
while (NULL != p->pNext)
{
if (RW_READ_LOCK != p->eLockMode)
bCanRunNow = false;
p = p->pNext;
}
if (RW_READ_LOCK != p->eLockMode)
bCanRunNow = false;
p->pNext = pNew;
}
if (bCanRunNow)
SetEvent(pNew->hEvent);
ReleaseMutex(rwlock->hMutex);
if (WAIT_OBJECT_0 !=
WaitForSingleObject(pNew->hEvent,
INFINITE))
return -1;
return 0;
}
int pthread_rwlock_unlock(pthread_rwlock_t *
rwlock)
{
pthread_rwlock_t_node *p;
Assert(NULL != rwlock);
if (WAIT_OBJECT_0 !=
WaitForSingleObject(rwlock->hMutex,
INFINITE))
return -1;
if (NULL == rwlock->pFirstNode)
{
ReleaseMutex(rwlock->hMutex);
return 0;
}
p = rwlock->pFirstNode;
rwlock->pFirstNode =
p->pNext;
CloseHandle(p->hEvent);
free(p);
if (NULL != rwlock->pFirstNode)
{
if (RW_READ_LOCK ==
rwlock->pFirstNode->eLockMode)
{
p = rwlock->pFirstNode;
while(NULL != p && RW_READ_LOCK ==
p->eLockMode)
{
SetEvent(p->hEvent);
p = p->pNext;
}
}
else
{
SetEvent(rwlock->pFirstNode->hEvent);
}
}
ReleaseMutex(rwlock->hMutex);
return 0;
}
int pthread_rwlock_wrlock(pthread_rwlock_t *
rwlock)
{
pthread_rwlock_t_node *p;
pthread_rwlock_t_node *pNew;
bool bCanRunNow = false;
Assert(NULL != rwlock);
if (WAIT_OBJECT_0 !=
WaitForSingleObject(rwlock->hMutex,
INFINITE))
return -1;
pNew =
(pthread_rwlock_t_node*)malloc(sizeof(pthread_rwlock_t_node));
if (NULL == pNew)
{
fprintf(stderr, "Out of memory\n");
ReleaseMutex(rwlock->hMutex);
return -1;
}
pNew->eLockMode = RW_WRITE_LOCK;
pNew->hEvent = CreateEvent(NULL, true, false,
NULL);
pNew->pNext = NULL;
if (INVALID_HANDLE_VALUE == pNew->hEvent)
{
ReleaseMutex(rwlock->hMutex);
free(pNew);
return -1;
}
if (NULL == rwlock->pFirstNode)
{
rwlock->pFirstNode = pNew;
bCanRunNow = true;
}
else
{
p = rwlock->pFirstNode;
while (NULL != p->pNext)
{
p = p->pNext;
}
p->pNext = pNew;
}
if (bCanRunNow)
SetEvent(pNew->hEvent);
ReleaseMutex(rwlock->hMutex);
if (WAIT_OBJECT_0 !=
WaitForSingleObject(pNew->hEvent,
INFINITE))
return -1;
return 0;
}
#endif
使用方法:
// pthread_rwlock_test.cpp : Defines the entry point for
the console application.
//
#include "stdafx.h"
#include "pthread_rwlock_test.h"
#include "pthread_rwlock.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// The one and only application object
CWinApp theApp;
using namespace std;
RWLockT lockdata;
HANDLE hMutex;
int counter = 1;
#define Log0(X) do{ LockMutex(hMutex); cout
<< (X)
<< endl; UnlockMutex(hMutex); }
while(0)
#define Log1(X, Y) do{ LockMutex(hMutex); cout
<< X <<
Y << endl; UnlockMutex(hMutex); }
while(0)
bool
LockMutex(HANDLE hMutex)
{
if (WAIT_OBJECT_0 != WaitForSingleObject(hMutex,
INFINITE))
return false;
return true;
}
bool UnlockMutex(HANDLE
hMutex)
{
return ReleaseMutex(hMutex);
}
DWORD WINAPI ThreadFunc(
LPVOID lpParam )
{ pthread_rwlock_t_lock_mode mod =
(pthread_rwlock_t_lock_mode)(int)lpParam;
if (mod == RW_READ_LOCK)
{
if
(!RWReadLock(&lockdata))
Log1( "Read
Error", GetLastError());
counter ++;
Sleep(1000);
Log1("read", counter);
}
else
{
if
(!RWWriteLock(&lockdata))
Log1( "Write
Error", GetLastError());
counter--;
Sleep(1000);
Log1("write", counter);
}
if
(counter < 0)
DebugBreak();
mod ==
RW_READ_LOCK ? --counter : ++ counter;
RWUnlock(&lockdata);
return
0;
}
int _tmain(int argc,
TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
//
initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL,
::GetCommandLine(), 0))
{
// TODO: change error code to
suit your needs
cerr
<< _T("Fatal Error: MFC
initialization failed") <<
endl;
nRetCode = 1;
}
else
{
hMutex = CreateMutex(NULL,
FALSE, NULL);
if
(!RWInitLock(&lockdata))
{
Log1("Init
error" , GetLastError());
return
0;
}
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_WRITE_LOCK, 0, NULL);
Sleep(100);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
Sleep(100);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_WRITE_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_WRITE_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_WRITE_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_WRITE_LOCK, 0, NULL);
Sleep(100);
CreateThread(NULL,
0, ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
CreateThread(NULL, 0,
ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
Sleep(100);
CreateThread(NULL,
0, ThreadFunc, (LPVOID)RW_WRITE_LOCK, 0, NULL);
Sleep(100);
CreateThread(NULL,
0, ThreadFunc, (LPVOID)RW_READ_LOCK, 0, NULL);
Sleep(20000);
RWCloseLock(&lockdata);
}
return nRetCode;
}