`
444878909
  • 浏览: 637995 次
文章分类
社区版块
存档分类
最新评论

读者写者问题(一)

 
阅读更多

阅读MoreWindows大神的秒杀多线程系列至第十一篇读者写着问题,做一点小小的总结;

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

本文对于写者开始写文件时就将可读事件(g_hEventCanRead)设置为未触发状态,结束写作时将可读事件(g_hEventCanRead)设置为触发状态;对于多个读者,使用一计数器ReadCount计数正在阅读的读者个数,当ReadCount=1时,设置可写事件(g_hEventCanWrite)为未触发状态,当ReadCount=0时,设置可写事件(g_hEventCanWrite)为触发状态。以此来保证读者与写者的同步与互斥。

程序1:

#include <stdio.h>
#include <windows.h>
#include <process.h>
const int READ_NUM = 5;

CRITICAL_SECTION g_cs,g_cs_reader_count;
/*
g_cs用来确保对stdout输出端的操作完整性;
g_cs_reader_count确保对readerCount计数的原子性
*/
HANDLE g_hEventCanRead,g_hEventCanWrite;
/*
g_hEventCanRead事件控制读者是否可读
g_hEventCanWrite事件控制写着是否可写
*/
int readerCount;
void WriterPrint(char *pstr)
{
    EnterCriticalSection(&g_cs);
    printf("\t%s\n",pstr);
    LeaveCriticalSection(&g_cs);
}
unsigned int __stdcall WriterFun(PVOID PM)
{
   WriterPrint("写者进入等待中。。。");
   WaitForSingleObject(g_hEventCanWrite,INFINITE);
   //Sleep(1000);
   ResetEvent(g_hEventCanRead);
   WriterPrint("写者开始写文件。。。");
   Sleep(100);
   WriterPrint("写者结束写文件。。。");

   SetEvent(g_hEventCanRead);
   return 0;
}
void ReadPrint(DWORD ID,char *pstr)
{
    EnterCriticalSection(&g_cs);
    printf("%d%s\n",ID,pstr);
    LeaveCriticalSection(&g_cs);
}
unsigned int __stdcall ReaderFun(PVOID PM)
{
     ReadPrint(GetCurrentThreadId(),"号读者进入等待。。。");
     WaitForSingleObject(g_hEventCanRead,INFINITE);
     EnterCriticalSection(&g_cs_reader_count);
     readerCount++;
     if(readerCount == 1)
        ResetEvent(g_hEventCanWrite);
     LeaveCriticalSection(&g_cs_reader_count);
     ReadPrint(GetCurrentThreadId(),"号读者开始阅读");
     ReadPrint(GetCurrentThreadId(),"号读者结束阅读");

     EnterCriticalSection(&g_cs_reader_count);
     readerCount--;
     if(readerCount == 0)
        SetEvent(g_hEventCanWrite);
     LeaveCriticalSection(&g_cs_reader_count);
     return 0;
}
int main()
{
    InitializeCriticalSection(&g_cs);
    InitializeCriticalSection(&g_cs_reader_count);

    //事件手动置位,初始为有信号TRUE
    g_hEventCanRead = CreateEvent(NULL,TRUE,TRUE,NULL);
    g_hEventCanWrite  = CreateEvent(NULL,TRUE,TRUE,NULL);
    readerCount = 0;

    int i;
    HANDLE handle[READ_NUM+1];
    for(i=1;i<=2;i++)
        handle[i] = (HANDLE)_beginthreadex(NULL,0,ReaderFun,NULL,0,NULL);

    handle[0] = (HANDLE)_beginthreadex(NULL,0,WriterFun,NULL,0,NULL);

    for(;i<=READ_NUM;i++)
        handle[i] = (HANDLE)_beginthreadex(NULL,0,ReaderFun,NULL,0,NULL);
    WaitForMultipleObjects(READ_NUM+1,handle,TRUE,INFINITE);

    for(i=0;i<=READ_NUM;i++)
        CloseHandle(handle[i]);

    CloseHandle(g_hEventCanRead);
    CloseHandle(g_hEventCanWrite);
    DeleteCriticalSection(&g_cs);
    DeleteCriticalSection(&g_cs_reader_count);
    return 0;
}
结果截图:

从运行结果可以看到:读者与写着的操作时互斥的。

但是,接着阅读下面的游客评论,找出其中BUG,产生BUG的片段如下:

   WriterPrint("写者进入等待中。。。");
   WaitForSingleObject(g_hEventCanWrite,INFINITE);
   ResetEvent(g_hEventCanRead);
   WriterPrint("写者开始写文件。。。");
   Sleep(100);
   WriterPrint("写者结束写文件。。。");

   SetEvent(g_hEventCanRead);
产生BUG的原因:写着在等待到可写事件(WaitForSingleObject(g_hEventCanWrite,INFINITE))的信号后,到置可读信号(ResetEvent(g-hEventCanRead))为未触发之前,读者线程可能获得权限,从而进行阅读的操作,但此时写者在等待到可写信号后,也在进行写作的操作,从而,没有保证读写的互斥。

将BUG片段稍做更改,即可体现:

unsigned int __stdcall WriterFun(PVOID PM)
{
   WriterPrint("写者进入等待中。。。");
   WaitForSingleObject(g_hEventCanWrite,INFINITE);
   WriterPrint("写者开始写文件。。。");
   Sleep(1000);
   ResetEvent(g_hEventCanRead);

   Sleep(100);
   WriterPrint("写者结束写文件。。。");

   SetEvent(g_hEventCanRead);
   return 0;
}
做如此更改,并没有改变程序的功能,但运行结果:


从结果看出,写者开始写文件到结束写文件之间,有读者在进行阅读,即程序没有实现读写的互斥。

是什么导致程序失去了读写的互斥性呢,个人看法是,没有保证读写的同步,个人认为只能先写后读,读者只有在写者的写作任务结束之后才能进行阅读,而程序1则使读者和写着一开始就都获得了可读和可写的权限,即在创建可读可写事件时,手动将事件设置为触发状态:

g_hEventCanRead = CreateEvent(NULL,TRUE,TRUE,NULL);
g_hEventCanWrite  = CreateEvent(NULL,TRUE,TRUE,NULL);
这才导致了写者开始写作但还没来及通知读者不可以阅读之前,读者就进行了阅读,是程序失去了读写的互斥性,所以,在创建事件时,可读事件应该手动设置为未触发状态,而在写着完成写作之后,才将可读事件设置为触发状态,这就保证了读写的互斥性。但这只是一个写者和多个读者的解决办法。更好的办法,是如MoreWindows大神的第十四篇文章读者写者问题继续 读写锁SRWLock中一样进行解决。按照我所想的代码实现如下:

程序2:

#include <stdio.h>
#include <windows.h>
#include <process.h>
const int READ_NUM = 5;

CRITICAL_SECTION g_cs,g_cs_reader_count;
/*
g_cs用来确保对stdout输出端的操作完整性;
g_cs_reader_count确保对readerCount计数的原子性
*/
HANDLE g_hEventCanRead,g_hEventCanWrite;
/*
g_hEventCanRead事件控制读者是否可读
g_hEventCanWrite事件控制写着是否可写
*/
int readerCount;
void WriterPrint(char *pstr)
{
    EnterCriticalSection(&g_cs);
    printf("\t%s\n",pstr);
    LeaveCriticalSection(&g_cs);
}
unsigned int __stdcall WriterFun(PVOID PM)
{
   WriterPrint("写者进入等待中。。。");
   WaitForSingleObject(g_hEventCanWrite,INFINITE);
   WriterPrint("写者开始写文件。。。");
   Sleep(1000);
   WriterPrint("写者结束写文件。。。");

   SetEvent(g_hEventCanRead);
   return 0;
}
void ReadPrint(DWORD ID,char *pstr)
{
    EnterCriticalSection(&g_cs);
    printf("%d%s\n",ID,pstr);
    LeaveCriticalSection(&g_cs);
}
unsigned int __stdcall ReaderFun(PVOID PM)
{
     ReadPrint(GetCurrentThreadId(),"号读者进入等待。。。");
     WaitForSingleObject(g_hEventCanRead,INFINITE);
     EnterCriticalSection(&g_cs_reader_count);
     readerCount++;
     if(readerCount == 1)
        ResetEvent(g_hEventCanWrite);
     LeaveCriticalSection(&g_cs_reader_count);
     ReadPrint(GetCurrentThreadId(),"号读者开始阅读");
     ReadPrint(GetCurrentThreadId(),"号读者结束阅读");

     EnterCriticalSection(&g_cs_reader_count);
     readerCount--;
     if(readerCount == 0)
        SetEvent(g_hEventCanWrite);
     LeaveCriticalSection(&g_cs_reader_count);
     return 0;
}
int main()
{
    InitializeCriticalSection(&g_cs);
    InitializeCriticalSection(&g_cs_reader_count);

    //事件手动置位,初始为有信号TRUE
    g_hEventCanRead = CreateEvent(NULL,TRUE,FALSE,NULL);
    g_hEventCanWrite  = CreateEvent(NULL,TRUE,TRUE,NULL);
    readerCount = 0;

    int i;
    HANDLE handle[READ_NUM+1];
    for(i=1;i<=2;i++)
        handle[i] = (HANDLE)_beginthreadex(NULL,0,ReaderFun,NULL,0,NULL);

    handle[0] = (HANDLE)_beginthreadex(NULL,0,WriterFun,NULL,0,NULL);

    for(;i<=READ_NUM;i++)
        handle[i] = (HANDLE)_beginthreadex(NULL,0,ReaderFun,NULL,0,NULL);
    WaitForMultipleObjects(READ_NUM+1,handle,TRUE,INFINITE);

    for(i=0;i<=READ_NUM;i++)
        CloseHandle(handle[i]);

    CloseHandle(g_hEventCanRead);
    CloseHandle(g_hEventCanWrite);
    DeleteCriticalSection(&g_cs);
    DeleteCriticalSection(&g_cs_reader_count);
    return 0;
}
结果:



从结果看出,读者和写着之间的操作实现了互斥操作。

总结,以上两段程序的思想有一些出入,仅个人写下作为以后提醒复习用之。

分享到:
评论

相关推荐

    读者写者问题写者优先实现

    写者优先的附加限制:如果一个读者申请进行读操作时已有另一个写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。 运行结果显示要求:要求在每个线程创建、发出读写申请、开始读写...

    东华大学 操作系统实验 读者写者问题 含源代码和报告

    在Windows2000环境下 创建一个控制台进程 此进程包含n个线程 用这n个线程来表示n个读者或写者 每个线程按相应测试数据文件 后面有介绍 的要求进行读写操作 用信号量机制分别实现读者优先和写者优先的读者 写者问题 ...

    操作系统课程设计读者-写者问题的实现

    在Windows 2000/XP环境下,使用多线程和信号量机制实现经典的读者写者问题,每个线程代表一个读者或一个写者。每个线程按相应测试数据文件的要求,进行读写操作。请用信号量机制分别实现读者优先和写者优先的读者-写...

    读者写者问题(linux)实现代码

    教材中对读者写者问题算法均有描述,但这个算法在不断地有读者流的情况下,写者会被阻塞。编写一个写者优先解决读者写者问题的程序,其中读者和写者均是多个进程,用信号量作为同步互斥机制。

    读者写者问题 (c实现)

    读者写者问题的算法模拟 操作系统实践项目 c语言的简单实现,读者写着问题 1. 多个读者可同时读(上限20) 2.只能有一个写者在写 3. 写者优先 vc6.0下编译通过

    C语言模拟读者写者问题

    写者优先的附加限制:如果一个读者申请进行读操作时已有另一个写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。 运行结果显示要求:要求在每个线程创建、发出读写申请、开始读写...

    读者写者问题的实现

    这是一个关于操作系统中关于读者写者问题的实现,通过简单易懂的c语言代码实现其功能,既可以让读者读入数据,也可以通过写着写出数据。

    操作系统课程设计 读者写者问题

    在Windows环境下,采用系统调用,编程实现读者、写者问题,具体的要求为:一个数据集(如一个文件或记录)为多个并发进程所共享,其中一些进程只要求读该数据集的内容,这些进程称为“读者”,而另一些进程则要求...

    读者写者问题

    读者写者问题读者写者问题读者写者问题读者写者问题读者写者问题

    华南理工大学操作系统实验:读者写者问题

    教材中对读者写者问题算法均有描述,但这个算法在不断地有读者流的情况下,写者会被阻塞。编写一个写者优先解决读者写者问题的程序,其中读者和写者均是多个进程,用信号量作为同步互斥机制。

    操作系统读者写者问题源程序

    #include ...//处理读者优先写者线程 void WriterFun(char* file); void W_ReaderThread(void *p); void W_WriterThread(void * 这个程序可以供大家参考,完全可以正确运行,得到自己想要的结果。

    通过研究经典的进程同步问题,采用“读写平等”的策略,用信号量 和 PV 操作实现对读者/写者问题的并发控制

    (3)读者和写者均有两个以上,可在程序运行期间动态增加读者与写者; (4)可读取样例数据(要求存放在外部文件中),进行读者/写者、进入内存时 间、读写时间的初始化; (5)要求将运行过程用可视化界面动态显示...

    操作系统实验报告 读者写者问题

    创建一个控制台进程。此进程包含n个线程。用这n个线 程来表示n个读者或写者。每个线程按相应测试数据文件 (后面有介绍)的要求进行读写操作。用信号量机制分别实 现读者优先和写者优先的读者-写者问题

    进程同步读者写者问题

    用三个算法实现读者写者问题,包括写优先、无优先、读优先等,下载即可使用。

    linux 操作系统 多线程编程 经典同步算法--读者写者问题

    有读者和写者两组并发进程,共享一个文件,当两个或以上的读进程同时访问共享数据时不会产生副作用,但若某个写进程和其他进程(读进程或写进程)同时访问共享数据时则可能导致数据不一致的错误。因此要求:①允许多...

    多线程模拟读者写者问题,采用读写平等方式

    操作系统课程设计采用读写平等实现的读者写者问题。

    操作系统实验多线程读者写者优先问题

    请用信号量机制分别实现读者优先和写者优先的读者-写者问题。 读者优先:如果一个读者申请进行读操作时已有另一读者正在进行读操作,则该读者可直接开始读操作。 写者优先:如果一个读者申请进行读操作时已有另一写...

    操作系统实验多线程读者写者优先问题.rar

    操作系统课程设计-读者写者问题,用C++ MFC实现的,可运行。

    进程线程之间的同步生产者消费者信号量读者写者写者优先

    1。生产者消费者问题(信号量+mutex) 参考教材中的生产者消费者算法,创建5个进程,其中两个进程为生产者进程,...编写一个写者优先解决读者写者问题的程序,其中读者和写者均是多个进程,用信号量作为同步互斥机制。

    java实现多线程间的同步与互斥(读者写者问题)

    用java实现多线程并发中的读者与写者问题,能够实现多线程对临界资源的同步有序访问。 具体实现为: 给定一个队列A[1-10][1-100000]、元素编号1-10,其中每个元素包含10万个随机数。创建若干个线程,各循环100次;...

Global site tag (gtag.js) - Google Analytics