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