读者写者问题描述非常简单,有一个写者很多读者,多个读者可以同时读文件,但写者在写文件时不允许有读者在读文件,同样有读者在读文件时写者也不去能写文件。

读者写者问题代码Java 读者写者问题流程图_读文件

上面是读者写者问题示意图,类似于生产者消费者问题的分析过程,首先来找找哪些是属于“等待”情况。

第一.写者要等到没有读者时才能去写文件。

第二.所有读者要等待写者完成写文件后才能去读文件。

找完“等待”情况后,再看看有没有要互斥访问的资源。由于只有一个写者而读者们是可以共享的读文件,所以按题目要求并没有需要互斥访问的资源。类似于上一篇中美观的彩色输出,我们对生产者输出代码进行了颜色设置(在控制台输出颜色设置参见《VC 控制台颜色设置》)。因此在这里要加个互斥访问,不然很有可能在写者线程将控制台颜色设置还原之前,读者线程就已经有输出了。所以要对输出语句作个互斥访问处理。

解决了互斥输出问题,接下来再考虑如何实现同步问题。可以设置一个变量来记录正在读文件的读者个数,第一个开始读文件的读者要负责将关闭允许写者进入的标志,最后一个结束读文件的读者要负责打开允许写者进入的标志。这样第一种“等待”情况就解决了。第二种“等待”情况是有写者进入时所以读者不能进入,使用一个事件就可以完成这个任务了——所有读者都要等待这个事件而写者负责触发事件和设置事件为未触发。详细见代码中注释:

#include "stdafx.h"
#include <stdio.h>  
#include <process.h>  
#include <windows.h> 



//设置控制台输出颜色 ; 
BOOL SetConsoleColor(WORD wAttributes)  
{  
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);  
    if (hConsole == INVALID_HANDLE_VALUE)  
        return FALSE;  
      
    return SetConsoleTextAttribute(hConsole, wAttributes);  
}  

const int READER_NUM = 5;  //读者个数  

//关键段和事件  
CRITICAL_SECTION g_cs, g_cs_writer_count;  
HANDLE g_hEventWriter, g_hEventNoReader;  
int g_nReaderCount; 

//读者线程输出函数(变参函数的实现)
void ReaderPrintf(char *pszFormat,...)
{
	va_list pArgList;

	va_start(pArgList,pszFormat);
	EnterCriticalSection(&g_cs);
	vfprintf(stdout ,pszFormat,pArgList);
	LeaveCriticalSection(&g_cs);
	va_end(pArgList);
}

unsigned int __stdcall ReaderThreadFun(PVOID pM)
{
	ReaderPrintf("编号为%d的读者进入等待中...\n",GetCurrentThreadId());
	//等待写者完成
	WaitForSingleObject(g_hEventWriter ,INFINITE);

	EnterCriticalSection(&g_cs_writer_count);
	g_nReaderCount++;
	if (g_nReaderCount == 1)
	{
		ResetEvent(g_hEventNoReader);
	}

	LeaveCriticalSection(&g_cs_writer_count);

	//读取文件
	ReaderPrintf("编号为%d的读者开始读取文件...\n", GetCurrentThreadId());  
	Sleep(rand() % 100);  

	//结束阅读,读者个数减小,空位增加  
	ReaderPrintf(" 编号为%d的读者结束读取文件\n", GetCurrentThreadId());  
 
	EnterCriticalSection(&g_cs_writer_count);
	g_nReaderCount--;
	if (g_nReaderCount == 0)
	{
		SetEvent(g_hEventNoReader);
	}
	LeaveCriticalSection(&g_cs_writer_count);

	return 0;

}

//写者线程输出函数  
void WriterPrintf(char *pszStr)  
{  
    EnterCriticalSection(&g_cs);  
    SetConsoleColor(FOREGROUND_GREEN);  
    printf("     %s\n", pszStr);  
    SetConsoleColor(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);  
    LeaveCriticalSection(&g_cs);  
} 

//写者线程函数
unsigned int __stdcall WriterThreadFun(PVOID pM)
{
    WriterPrintf("写者线程进入等待中...");  
   //等待读文件的读者为零  
    WaitForSingleObject(g_hEventNoReader, INFINITE);  
   //标记写者正在写文件  
    ResetEvent(g_hEventWriter);  
         
   //写文件  
    WriterPrintf("  写者开始写文件.....");  
    Sleep(rand() % 100);  
    WriterPrintf("  写者结束写文件");  
	//标记写者结束写文件  
    SetEvent(g_hEventWriter);  
	return 0;

}

int main()
{
   printf("  读者写者问题\n");  
 
   //初始化事件和信号量  
   InitializeCriticalSection(&g_cs);  
   InitializeCriticalSection(&g_cs_writer_count);  
  
  //手动置位,初始已触发  
    g_hEventWriter = CreateEvent(NULL, TRUE, TRUE, NULL);  
    g_hEventNoReader  = CreateEvent(NULL, FALSE, TRUE, NULL);  
    g_nReaderCount = 0;  
  
    int i;  
    HANDLE hThread[READER_NUM + 1];

	//先启动两个读者线程;
    for (i = 1; i <= 2; i++)  
        hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);  
  
	//启动写者线程  ;
    hThread[0] = (HANDLE)_beginthreadex(NULL, 0, WriterThreadFun, NULL, 0, NULL);  
     Sleep(50);  

    //最后启动其它读者结程;  
   for ( ; i <= READER_NUM; i++)  
        hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ReaderThreadFun, NULL, 0, NULL);  
    
   WaitForMultipleObjects(READER_NUM + 1, hThread, TRUE, INFINITE); 

    for (i = 0; i < READER_NUM + 1; i++)  
       CloseHandle(hThread[i]);  
  
   //销毁事件和信号量  
    CloseHandle(g_hEventWriter);  
    CloseHandle(g_hEventNoReader);  
    DeleteCriticalSection(&g_cs);  
    DeleteCriticalSection(&g_cs_writer_count);  
    return 0; 

}

读者写者问题代码Java 读者写者问题流程图_互斥_02