读写锁实际是一种特殊的自旋锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进行读访问,写者则需要对共享资源进行写操作。这种锁相对于自旋锁而言,能提高并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最大可能的读者数为实际的逻辑CPU数。写者是排他性的,一个读写锁同时只能有一个写者或多个读者(与CPU数相关),但不能同时既有读者又有写者。
现在Win32的API,用C++实现自己的读写锁。这组API包括:CreateMutex,CreateEvent,WaitForSingleObject,WaitForMultipleObjects,ResetEvent,ReleaseMutex,SetEvent,CloseHandle。以下代码在VS2005下,已经编译通过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
//RWLockImpl.h <span style="font-size:16px;">#ifndef _RWLockImpl_Header #define _RWLockImpl_Header #include <assert.h> #include <iostream> #include <Windows.h> #include <process.h> using namespace std; /* 读写锁允许当前的多个读用户访问保护资源,但只允许一个写读者访问保护资源 */ //----------------------------------------------------------------- class CRWLockImpl { protected: CRWLockImpl(); ~CRWLockImpl(); void ReadLockImpl(); bool TryReadLockImpl(); void WriteLockImpl(); bool TryWriteLockImpl(); void UnlockImpl(); private: void AddWriter(); void RemoveWriter(); DWORD TryReadLockOnce(); HANDLE m_mutex; HANDLE m_readEvent; HANDLE m_writeEvent; unsigned m_readers; unsigned m_writersWaiting; unsigned m_writers; }; //----------------------------------------------------------------- class CMyRWLock: private CRWLockImpl { public: //创建读/写锁 CMyRWLock(){}; //销毁读/写锁 ~CMyRWLock(){}; //获取读锁 //如果其它一个线程占有写锁,则当前线程必须等待写锁被释放,才能对保护资源进行访问 void ReadLock(); //尝试获取一个读锁 //如果获取成功,则立即返回true,否则当另一个线程占有写锁,则返回false bool TryReadLock(); //获取写锁 //如果一个或更多线程占有读锁,则必须等待所有锁被释放 //如果相同的一个线程已经占有一个读锁或写锁,则返回结果不确定 void WriteLock(); //尝试获取一个写锁 //如果获取成功,则立即返回true,否则当一个或更多其它线程占有读锁,返回false //如果相同的一个线程已经占有一个读锁或写锁,则返回结果不确定 bool TryWriteLock(); //释放一个读锁或写锁 void Unlock(); private: CMyRWLock(const CMyRWLock&); CMyRWLock& operator = (const CMyRWLock&); }; inline void CMyRWLock::ReadLock() { ReadLockImpl(); } inline bool CMyRWLock::TryReadLock() { return TryReadLockImpl(); } inline void CMyRWLock::WriteLock() { WriteLockImpl(); } inline bool CMyRWLock::TryWriteLock() { return TryWriteLockImpl(); } inline void CMyRWLock::Unlock() { UnlockImpl(); } #endif</span> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
//RWLockImpl.cpp <span style="font-size:16px;">#include "RWLockImpl.h" CRWLockImpl::CRWLockImpl(): m_readers(0), m_writersWaiting(0), m_writers(0) { m_mutex = CreateMutex(NULL, FALSE, NULL); if (m_mutex == NULL) cout<<"cannot create reader/writer lock"<<endl; m_readEvent = CreateEvent(NULL, TRUE, TRUE, NULL); if (m_readEvent == NULL) cout<<"cannot create reader/writer lock"<<endl; m_writeEvent = CreateEvent(NULL, TRUE, TRUE, NULL); if (m_writeEvent == NULL) cout<<"cannot create reader/writer lock"<<endl; } CRWLockImpl::~CRWLockImpl() { CloseHandle(m_mutex); CloseHandle(m_readEvent); CloseHandle(m_writeEvent); } inline void CRWLockImpl::AddWriter() { switch (WaitForSingleObject(m_mutex, INFINITE)) { case WAIT_OBJECT_0: if (++m_writersWaiting == 1) ResetEvent(m_readEvent); ReleaseMutex(m_mutex); break; default: cout<<"cannot lock reader/writer lock"<<endl; } } inline void CRWLockImpl::RemoveWriter() { switch (WaitForSingleObject(m_mutex, INFINITE)) { case WAIT_OBJECT_0: if (--m_writersWaiting == 0 && m_writers == 0) SetEvent(m_readEvent); ReleaseMutex(m_mutex); break; default: cout<<"cannot lock reader/writer lock"<<endl; } } void CRWLockImpl::ReadLockImpl() { HANDLE h[2]; h[0] = m_mutex; h[1] = m_readEvent; switch (WaitForMultipleObjects(2, h, TRUE, INFINITE)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: ++m_readers; ResetEvent(m_writeEvent); ReleaseMutex(m_mutex); assert(m_writers == 0); break; default: cout<<"cannot lock reader/writer lock"<<endl; } } bool CRWLockImpl::TryReadLockImpl() { for (;;) { if (m_writers != 0 || m_writersWaiting != 0) return false; DWORD result = TryReadLockOnce(); switch (result) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: return true; case WAIT_TIMEOUT: continue; default: cout<<"cannot lock reader/writer lock"<<endl; } } } void CRWLockImpl::WriteLockImpl() { AddWriter(); HANDLE h[2]; h[0] = m_mutex; h[1] = m_writeEvent; switch (WaitForMultipleObjects(2, h, TRUE, INFINITE)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: --m_writersWaiting; ++m_readers; ++m_writers; ResetEvent(m_readEvent); ResetEvent(m_writeEvent); ReleaseMutex(m_mutex); assert(m_writers == 1); break; default: RemoveWriter(); cout<<"cannot lock reader/writer lock"<<endl; } } bool CRWLockImpl::TryWriteLockImpl() { AddWriter(); HANDLE h[2]; h[0] = m_mutex; h[1] = m_writeEvent; switch (WaitForMultipleObjects(2, h, TRUE, 1)) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: --m_writersWaiting; ++m_readers; ++m_writers; ResetEvent(m_readEvent); ResetEvent(m_writeEvent); ReleaseMutex(m_mutex); assert(m_writers == 1); return true; case WAIT_TIMEOUT: RemoveWriter(); default: RemoveWriter(); cout<<"cannot lock reader/writer lock"<<endl; } return false; } void CRWLockImpl::UnlockImpl() { switch (WaitForSingleObject(m_mutex, INFINITE)) { case WAIT_OBJECT_0: m_writers = 0; if (m_writersWaiting == 0) SetEvent(m_readEvent); if (--m_readers == 0) SetEvent(m_writeEvent); ReleaseMutex(m_mutex); break; default: cout<<"cannot unlock reader/writer lock"<<endl; } } DWORD CRWLockImpl::TryReadLockOnce() { HANDLE h[2]; h[0] = m_mutex; h[1] = m_readEvent; DWORD result = WaitForMultipleObjects(2, h, TRUE, 1); switch (result) { case WAIT_OBJECT_0: case WAIT_OBJECT_0 + 1: ++m_readers; ResetEvent(m_writeEvent); ReleaseMutex(m_mutex); assert(m_writers == 0); return result; case WAIT_TIMEOUT: default: cout<<"cannot lock reader/writer lock"<<endl; } return result; } </span> |
下边是测试代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
<span style="font-size:16px;">// MyRWLockWin32.cpp : 定义控制台应用程序的入口点。 // #include "RWLockImpl.h" //创建一个读写锁对象 CMyRWLock g_myRWLock; volatile int g_counter = 0; //线程函数 unsigned int __stdcall StartThread(void *pParam) { int lastCount = 0; for (int i = 0; i < 10000; ++i) { g_myRWLock.ReadLock(); lastCount = g_counter; //在读锁域,两个线程不断循环交替访问全局变量g_counter for (int k = 0; k < 100; ++k) { if (g_counter != lastCount) cout<<"the value of g_counter has been updated."<<endl; Sleep(0); } g_myRWLock.Unlock(); g_myRWLock.WriteLock(); //在写锁域,只有一个线程可以修改全局变量g_counter的值 for (int k = 0; k < 100; ++k) { --g_counter; Sleep(0); } for (int k = 0; k < 100; ++k) { ++g_counter; Sleep(0); } ++g_counter; if (g_counter <= lastCount) cout<<"the value of g_counter is error."<<endl; g_myRWLock.Unlock(); } return (unsigned int)0; } int main(int argc, char* argv[]) { HANDLE hThread1, hThread2; unsigned int uiThreadId1, uiThreadId2; //创建两个工作线程 hThread1 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)NULL, 0, &uiThreadId1); hThread2 = (HANDLE)_beginthreadex(NULL, 0, &StartThread, (void *)NULL, 0, &uiThreadId2); //等待线程结束 DWORD dwRet = WaitForSingleObject(hThread1,INFINITE); if ( dwRet == WAIT_TIMEOUT ) { TerminateThread(hThread1,0); } dwRet = WaitForSingleObject(hThread2,INFINITE); if ( dwRet == WAIT_TIMEOUT ) { TerminateThread(hThread2,0); } //关闭线程句柄,释放资源 CloseHandle(hThread1); CloseHandle(hThread2); assert (g_counter == 20000); system("pause"); return 0; }</span> |
发表评论
要发表评论,您必须先登录。