1 void Read() 2 { 3 Lock(mutex); 4 5 // 读取数据 6 7 UnLock(mutex); 8 } 9 10 void Write() 11 { 12 Lock(mutex); 13 14 // 写入数据 15 16 UnLock(mutex); 17 }
读写锁的设计
1 void Read() 2 { 3 Wait(condition); 4 5 Lock(mutex); 6 if(0 == Count++) 7 Lock(semaphore); 8 UnLock(mutex); 9 10 // 读取数据 11 12 Lock(mutex); 13 if(0 == --Count) 14 UnLock(semaphore); 15 UnLock(mutex); 16 } 17 18 void Write() 19 { 20 Destroy(condition); 21 Lock(semaphore); 22 23 // 写入数据 24 25 UnLock(semaphore); 26 Create(condition); 27 }
在代码中,信号量semaphore的初值为1,为了读-写能够排他和写-写排他这两个关系。Count记录有多少个读操作,而mutex是为了保证Count线程安全。忽略condition相关的代码,可以说,已经实现了前面提到的读写锁。但为什么加入condition呢?原因是这样的,如果有多个线程在连续进行读操作,可能导致长时间不能进行写操作,也就是通常说的写锁饥饿。condition可以解决这个问题,如果有线程正在等待写操作,那么新的读操作先等待,等到写操作完成后再开始。这样可以保证获得读写操作的机会是相对公平的。
1 // 实现代码 2 3 class RWLock 4 { 5 public: 6 RWLock(); 7 ~RWLock(); 8 public: 9 void AcquireReadLock(); 10 void ReleaseReadLock(); 11 void AcquireWriteLock(); 12 void ReleaseWriteLock(); 13 private: 14 volatile DWORD m_cnt; 15 CRITICAL_SECTION m_cs; 16 HANDLE m_evt; 17 HANDLE m_sem; 18 }; 19 20 RWLock::RWLock() 21 : m_cnt(0) 22 , m_evt(NULL) 23 , m_cs(NULL) 24 , m_sem(NULL) 25 { 26 // 提倡的做法,在专门的初始化函数里创建和初始化这些变量 27 28 ::InitializeCriticalSection(&m_cs); 29 30 // Event初始处于激活状态,且必须是手动重置,否则存在死锁隐患,即等待Event前,先被激活了 31 m_evt = ::CreateEvent(NULL, TRUE, TRUE, NULL); 32 m_sem = ::CreateSemaphore(NULL, 1, 1, NULL); 33 } 34 35 RWLock::~RWLock() 36 { 37 ::CloseHandle(m_sem); 38 ::CloseHandle(m_evt); 39 ::DeleteCriticalSection(&m_cs); 40 } 41 42 void RWLock::AcquireReadLock() 43 { 44 ::WaitForSingleObject(m_evt, INFINITE); 45 46 ::EnterCriticalSection(&m_cs); 47 if(0 == m_cnt++) 48 ::WaitForSingleObject(m_sem, INFINITE); 49 ::LeaveCriticalSection(&m_cs); 50 } 51 52 void RWLock::ReleaseReadLock() 53 { 54 ::EnterCriticalSection(&m_cs); 55 if(0 == --m_cnt) 56 ::ReleaseSemaphore(m_sem, 1, NULL); 57 ::LeaveCriticalSection(&m_cs); 58 } 59 60 void RWLock::AcquireWriteLock() 61 { 62 ::ResetEvent(m_evt); 63 ::WaitForSingleObject(m_sem, INFINITE); 64 } 65 66 void RWLock::ReleaseWriteLock() 67 { 68 ::ReleaseSemaphore(m_sem, 1, NULL); 69 ::SetEvent(m_evt); 70 } 71 72 // 使用示例 73 74 void Read() 75 { 76 // 支持多个线程读取数据 77 78 rwLock.AcquireReadLock(); 79 80 // 读取数据 81 82 rwLock.ReleaseReadLock(); 83 } 84 85 void Write() 86 { 87 rwLock.AcquireWriteLock(); 88 89 // 写入数据 90 91 rwLock.ReleaseWriteLock(); 92 }
原文:http://www.cnblogs.com/coldberry/p/ReadWriteLock.html