【多线程】(十)读者写者问题

参考自: http://blog.csdn.net/morewindows/article/details/7596034#

 

 

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

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

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

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

找完“等待”情况后,再看看有没有要互斥访问的资源。由于只有一个写者而读者们是可以共享的读文件,所以按题目要求并没有需要互斥访问的资源。类似于上一篇中美观的彩色输出,我们对生产者输出代码进行了颜色设置(在控制台输出颜色设置参见《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; 

}


 

 

 

 

初始条件: 1操作系统:Linux 或者 windows 2程序设计语言:C,java语言 3设有20个连续的存储单元,写入/读出的数据项按增序设定为1-20这20个字符。 要求完成的主要任务: (包括课程设计工作量及其技术要求,以及说明书撰写等具体要求) 1.技术要求: 1)为每个读者写者产生一个线程,设计正确的同步算法 2)每个读者/写者对该存储区进行操作后,即时显示该存储区的全部内容、当前指针位置和读者/写者线程的自定义标识符。。 3)读者应有3个以上,写者应有有两个以上。 4)多个读者/写者之间须共享对存储区进行操作的函数代码。 2. 设计说明书内容要求: 1)设计题目与要求 2)总的设计思想及系统平台、语言、工具等。 3)数据结构与模块说明(功能与流程图) 4)给出用户名、源程序名、目标程序名和源程序及其运行结果。(要注明存储各个程序及其运行结果的主机IP地址和目录。) 5)运行结果与运行情况 (提示: (1)连续存储区可用数组实现。 (2)编译命令可用:     cc -lpthread -o  目标文件名  源文件名 (3)多线程编程方法参见附件。) 3. 调试报告: 1) 调试记录 2) 自我评析和总结 上机时间安排: 19周一 ~ 五 下午14:00 - 18:00 (6月27日开始) 指导教师签名: 年 月 日 系主任(或责任教师)签名: 年 月 日 五、源代码 #include #include #include "fstream.h" int readcount=0; //读者数目 int writecount=0; //写者数目 CRITICAL_SECTION RP_Write; //临界区 CRITICAL_SECTION cs_Write; CRITICAL_SECTION cs_Read; struct ThreadInfo //线程信息 { int Threadhao; //线程序号 char ThreadClass; //线程类别 double ThreadStartTime; //线程开始时间 double ThreadRunTime; //线程读写持续时间 }; void ReaderFun(char* file);//读者优先函数 void R_ReaderThread(void *p);//处理读者优先读者线程 void R_WriterThread(void *p);//处理读者优先写者线程 void WriterFun(char* file); void W_ReaderThread(void *p); void W_WriterThread(void *p); int main()//主函数 { char select; while (true) { cout<<"***************本程序实现读者-写者问题*******\n"<<endl; cout<<" 1:读者优先"<<endl; cout<<" 2:写者优先"<<endl; cout<<" 3:退出"<<endl; cout<<"\n*********************************************"<<endl; cout<<"请选择要进行的操作:"<>select; if(select!='1' && select!='2' && select!='3') cout<<"你操作有误,请重试!"<<endl; }while (select!='1' && select!='2' && select!='3'); system("cls"); if (select=='3') return 0;//退出 else if (select=='1')//调用读者优先 ReaderFun("peizhi.txt"); else if(select=='2')//调用写者优先 WriterFun("peizhi.txt"); cout<<"\n是否还有继续? 1. 继续 2.退出"<>select; if(select!='1' && select!='2' ) cout<<"你操作有误,请重试!"<<endl; }while (select!='1' && select!='2'); if(select=='2') return 0;// 退出 system("cls"); } return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值