读写锁在对资源进行保护的同时,还能区分想要读取资源值的线程(读取者线程)和想要更新资源的线程(写入者线程)。
对于读取者线程,读写锁会允许他们并发的执行。当有写入者线程在占有资源时,读写锁会让其它写入者线程和读取者线程等待。
因此用读写锁来解决读者写者问题会使代码非常清晰和简洁。
SRWLock 允许我们区分那些想要读取资源的值的线程(读取者线程)和想要更新资源值的线程(写入者线程)
所有的读取者线程在同一时刻访问共享资源是可以的,这是因为仅仅读取资源的值并不存在破坏数据的风险。
只有当写入者线程想要对资源进行更新的时候才需要同步。
在这种情况下,写入者线程应该独占对资源的访问权: 任何其他线程,无论是读取者线程还是写入者线程,都不允许访问资源。
相关函数介绍:
第一个 InitializeSRWLock
函数功能:初始化读写锁
函数原型:VOID InitializeSRWLock(PSRWLOCK SRWLock);
函数说明:初始化(没有删除或销毁SRWLOCK的函数,系统会自动清理)
第二个 AcquireSRWLockExclusive
函数功能:写入者线程申请写资源。
函数原型:VOID AcquireSRWLockExclusive(PSRWLOCK SRWLock);
第三个 ReleaseSRWLockExclusive
函数功能:写入者线程写资源完毕,释放对资源的占用。
函数原型:VOID ReleaseSRWLockExclusive(PSRWLOCK SRWLock);
第四个 AcquireSRWLockShared
函数功能:读取者线程申请读资源。
函数原型:VOID AcquireSRWLockShared(PSRWLOCK SRWLock);
第五个 ReleaseSRWLockShared
函数功能:读取者线程结束读取资源,释放对资源的占用。
函数原型:VOID ReleaseSRWLockShared(PSRWLOCK SRWLock);
注意一个线程仅能锁定资源一次,不能多次锁定资源。
实例代码如下:
#include <iostream> #include <windows.h> #include <process.h> using namespace std; const int NUM = 30, READER_SIZE = 10; HANDLE thread_r[NUM], thread_o[NUM], thread_w[NUM]; CRITICAL_SECTION sc, oc; SRWLOCK rwLock; unsigned int __stdcall read(PVOID pm) { AcquireSRWLockShared(&rwLock); EnterCriticalSection(&sc); cout << GetCurrentThreadId() << "号,读进程开始..." << endl; LeaveCriticalSection(&sc); Sleep(rand() % 100); EnterCriticalSection(&sc); cout << GetCurrentThreadId() << "号,读进程结束..." << endl; LeaveCriticalSection(&sc); ReleaseSRWLockShared(&rwLock); return 0; } unsigned int __stdcall write(PVOID pm) { AcquireSRWLockExclusive(&rwLock); cout << GetCurrentThreadId() << "号,--------------写进程开始..." << endl; Sleep(rand() % 100); cout << GetCurrentThreadId() << "号,--------------写进程执行完毕..." << endl; ReleaseSRWLockExclusive(&rwLock); return 0; } int main() { InitializeCriticalSection(&sc); InitializeCriticalSection(&oc); InitializeSRWLock(&rwLock); int i = 0; for(; i<NUM; i++) { thread_r[i] = (HANDLE) _beginthreadex(NULL, 0, read, NULL, 0, NULL); thread_w[i] = (HANDLE) _beginthreadex(NULL, 0, write, NULL, 0, NULL); } WaitForMultipleObjects(NUM, thread_r, TRUE, INFINITE); // Sleep(100); // 在执行30个 读线程 for(i=0; i<NUM; i++) { thread_o[i] = (HANDLE) _beginthreadex(NULL, 0, read, NULL, 0, NULL); } // writeLock = true; WaitForMultipleObjects(NUM, thread_w, TRUE, INFINITE); WaitForMultipleObjects(NUM, thread_o, TRUE, INFINITE); DeleteCriticalSection(&sc); DeleteCriticalSection(&oc); cout << "运行完毕" << endl; getchar(); return 0; }
运行效果如下:
总结一下读写锁SRWLock
1.读写锁声明后要初始化,但不用销毁,系统会自动清理读写锁。
2.读取者和写入者分别调用不同的申请函数和释放函数。