// Reader_Writer.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include<Windows.h>
#include<process.h>
using namespace std;
HANDLE gEventNoReader=0,gEventWriting=0;
int gReaderCount=0;
const int READER_NUM = 5; //读者个数
CRITICAL_SECTION g_cs;
DWORD ReadFunc(LPVOID)
{
//在读者数量不是1的情况下不需要等待,但是呢又指定 代码只能同时又一个线程运行 所以在gReaderCount不是 1 的情况下其他线程进不来这段代码
::EnterCriticalSection(&g_cs);
gReaderCount++;
if(gReaderCount==1)
{
//第一个读者读文件的时候做标记,不允许写文件
//开始等待事件
::WaitForSingleObject(gEventWriting,INFINITE);
cout<<"第一个读者开始读取\n";
::ResetEvent(gEventWriting);
}
::LeaveCriticalSection(&g_cs);
cout<<"读者正在读文件\n";
//::Sleep(100);
::EnterCriticalSection(&g_cs);
gReaderCount--;
if(gReaderCount==0)
{
//最后一个读者负责做标记告诉写进程没有读者了,可以写文件了
cout<<"最后一个读者读取: ";
::SetEvent(gEventNoReader);
}
::LeaveCriticalSection(&g_cs);
cout<<"读者结束等待读取文件\n";
return 0;
}
DWORD WriteFun(LPVOID lp)
{
::WaitForSingleObject(gEventNoReader,INFINITE);
//通知读者不可以读文件了
::ResetEvent(gEventWriting);
cout<<"开始进行写文件\n";
cout<<"写文件结束\n";
::SetEvent(gEventWriting);
return 0;
}
int main()
{
gEventNoReader=::CreateEvent(NULL,FALSE,TRUE,NULL);
gEventWriting=::CreateEvent(NULL,true,true,NULL);
::InitializeCriticalSection(&g_cs);
//先启动两个读者进程
HANDLE hThread[READER_NUM+1]={0};
int i=0;
DWORD TMP=0;
for(i=1;i<2;i++)
{
hThread[i]=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadFunc,NULL,0,&TMP);
}
//开启写线程
hThread[0]=::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WriteFun,NULL,0,&TMP);
for ( ; i <= READER_NUM; i++)
hThread[i] =CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadFunc,NULL,0,&TMP);
WaitForMultipleObjects(READER_NUM + 1, hThread, TRUE, INFINITE);
for (i = 0; i < READER_NUM + 1; i++)
CloseHandle(hThread[i]);
CloseHandle(gEventNoReader);
CloseHandle(gEventWriting);
::DeleteCriticalSection(&g_cs);
}
这个过程就是在第一个读者在读取的时候,我们需要进行写的设置,告诉写进程,现在不要进行写操作,而在最后一个读者读取的时候恢复,告诉写进程现在可以进行写操作了
同时写进程操作的时候也要告诉读进程现在不要读了,我正在写,而对记录读者个数的全局变量进行操作的时候,我们要记住必须是原子操作,也即这段代码的执行必须同时只有一个线程才可以