第一 写者要等到没有读者时才能去写文件。
第二 所有读者要等待写者完成写文件后才能去读文件。
1. 对互斥量进行判断时,在进入关键段后还要在判断一次,实现双重检测。
2. 在读线程的第一个关键段中,使用旋转锁,可以避免在第二个关键段中,别的线程提前释放写者互斥量的情况。
3. 在写者中,只是做了比较简单的判断,来实现和读者的互斥运行。
#include <iostream>
#include <windows.h>
#include <process.h>
using namespace std;
const int NUM = 30, READER_SIZE = 10;
HANDLE readS;
int readThNum,total;
HANDLE thread_r[NUM], thread_o[NUM], thread_w[NUM];
CRITICAL_SECTION sc, oc;
bool readLock, writeLock, reverseLock;
// 读线程
unsigned int __stdcall read(PVOID pm) {
// 持续循环检测writeLock状态位
while(1) {
if(readLock) {
WaitForSingleObject(readS, INFINITE);
EnterCriticalSection(&sc);
// 再次检测
if(!readLock) {
cout << "reversed" << endl;
// 使用旋转锁,来避免当readThNum为0时的重复读取
while(reverseLock) {
Sleep(50);
}
}
total++;
readThNum++;
cout << GetCurrentThreadId() << "号,读进程开始..." << endl;
LeaveCriticalSection(&sc);
// do something...
Sleep(rand() % 300);
EnterCriticalSection(&sc);
readThNum--;
if(readThNum == 0) {
readLock = false;
reverseLock = true;
writeLock = true;
}
cout << " " << GetCurrentThreadId() << "号,读进程执行完毕..." << endl;
LeaveCriticalSection(&sc);
ReleaseSemaphore(readS, 1, NULL);
break;
} else {
Sleep(50);
}
}
return 0;
}
// 写线程
unsigned int __stdcall write(PVOID pm) {
// 持续循环检测writeLock状态位
while(1) {
if(writeLock) {
EnterCriticalSection(&oc);
if(writeLock) {
cout << GetCurrentThreadId() << "号,--------------写进程开始..." << endl;
Sleep(100);
cout << GetCurrentThreadId() << "号,--------------写进程执行完毕..." << endl;
// 检测读线程是否已经执行完毕
if(total != 2*NUM) {
writeLock = false;
}
readLock = true;
reverseLock = false;
LeaveCriticalSection(&oc);
break;
} else {
LeaveCriticalSection(&oc);
}
}
Sleep(50);
}
return 0;
}
int main() {
readLock = true;
writeLock = false;
reverseLock = false;
readS = CreateSemaphore(NULL, READER_SIZE, READER_SIZE, NULL);
InitializeCriticalSection(&sc);
InitializeCriticalSection(&oc);
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);
CloseHandle(readS);
cout << "运行完毕" << endl;
getchar();
return 0;
}
运行效果如下: