读写锁在对资源进行保护的同时,还能区分想要读取资源值的线程(读取者线程)和想要更新资源的线程(写入者线程)。
对于读取者线程,读写锁会允许他们并发的执行。当有写入者线程在占有资源时,读写锁会让其它写入者线程和读取者线程等待。
因此用读写锁来解决读者写者问题会使代码非常清晰和简洁。
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.读取者和写入者分别调用不同的申请函数和释放函数。