进程同步互斥——读者写者问题

经过几天的尝试与努力,初步实现了操作系统实验设计三个题目中最简单的一个:编程模拟进程的同步与互斥。真是煞费苦心。没有可视化的操作界面,完全用C/C++来进行模拟,着实难受。

在自己对同步互斥的理解的基础上,借鉴别人的一些实现方法,终于将代码初步敲打出来。代码不多,却也复杂。下面简单对程序做下介绍。

(一)实验目的

进一步理解 “临界资源” 的概念;

把握在多个进程并发执行过程中对临界资源访问时的必要约束条件;

理解操作系统原理中 “互斥” 和 “同步” 的涵义。

(二)实验内容

利用程序设计语言编程,模拟并发执行进程的同步与互斥(要求:进程数目不少于 3 个)。

(三)、程序分析

读者写者问题的定义如下:有一个许多进程共享的数据区,这个数据区可以是一个文件或者主存的一块空间;有一些只读取这个数据区的进程(Reader)和一些只往数据区写数据的进程(Writer),此外还需要满足以下条件:

(1) 任意多个读进程可以同时读这个文件;

(2) 一次只有一个写进程可以往文件中写;

(3) 如果一个写进程正在进行操作,禁止任何读进程度文件。

 

实验要求用信号量来实现读者写者问题的调度算法。实验提供了signal类,该类通过P( )、V( )两个方法实现了P、V原语的功能。实验的任务是修改Creat_Writer()添加写者进程,Creat_Reader()创建读者进程。Reader_goon()读者进程运行函数。


Ø

读优先:要求指一个读者试图进行读操作时,如果这时正有其他读者在进行操作,他可直接开始读操作,而不需要等待。
读者优先的附加限制:如果一个读者申请进行读操作时已有另一读者正在进行读操作,则该读者可直接开始读操作。

Ø

写优先:一个读者试图进行读操作时,如果有其他写者在等待进行写操作或正在进行写操作,他要等待该写者完成写操作后才开始读操作。

写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态后才能开始读操作。


在Windows 2000/XP 环境下,创建一个控制台进程,此进程包含 n 个线程。用这 n 个线程来表示 n 个读者或写者。每个线程按相应测试数据文件(格式见下)的要求进行读写操作。用信号量机制分别实现读者优先和写者优先的读者/写者问题。

运行结果显示要求:要求在每个线程创建、发出读写操作申请、开始读写操作和结束读写操作时分别显示一行提示信息,以确定所有处理都遵守相应的读写操作限制。

 

测试数据文件包括 n 行测试数据,分别描述创建的 n 个线程是读者还是写者,以及读写操作的开始时间和持续时间。每行测试数据包括4个字段,各个字段间用空格分隔。

Ø        第一个字段为一个正整数,表示线程序号

Ø        第二个字段表示相应线程角色,R 表示读者,W 表示写者

Ø        第三个字段为一个正数,表示读/写操作的开始时间:线程创建后,延迟相应时间(单位为秒)后发出对共享资源的读/写请求

Ø        第四个字段为一正数,表示读/写操作的持续时间:线程读写请求成功后,开始对共享资源的读/写操作,该操作持续相应时间后结束,并释放共享资源

例如:

1 R 3 5

2 W 4 5

3 R 5 2

4 R 6 5

5 W 5.1 3

读者写者问题是操作系统中经典的互斥问题:一块数据被多个读者和写者的访问,需要考虑读写互斥、写写互斥(可以同时由多个读者读取)。具体的又可以分为读者优先和写者优先两类。

读者优先算法:

当新的读者到来的时候,若当前正有读者在进行读操作,则该读者无需等待前面的写操作完成,直接进行读操作。

设置两个互斥信号量:

rwmutex 用于写者与其他读者/写者互斥的访问共享数据

rmutex 用于读者互斥的访问读者计数器readcount

var rwmutex, rmutex : semaphore := 1,1 ;

int readcount = 0;

cobegin

       readeri begin // i=1,2,….

              P(rmutex);

              Readcount++;

              If (readcount == 1) P(rwmutex);

              V(rmutex);

              读数据;

              P(rmutex);

              Readcount--;

              If (readcount == 0) V(rwmutex);

              V(rmutex);

       End

       Writerj begin // j = 1,2,….

              P(rwmutex);

              写更新;

              V(rwmutex);

       End

Coend

写者优先:

条件:

1)多个读者可以同时进行读

2)写者必须互斥(只允许一个写者写,也不能读者写者同时进行)

3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)

设置三个互斥信号量:

rwmutex 用于写者与其他读者/写者互斥的访问共享数据

rmutex 用于读者互斥的访问读者计数器readcount

nrmutex 用于写者等待已进入读者退出,所有读者退出前互斥写操作

var rwmutex, rmutex,nrmutex : semaphore := 1,1,1 ;

int readcount = 0;

cobegin

       readeri begin // i=1,2,….

              P(rwmutex);

              P(rmutex);

              Readcount++;

              If (readcount == 1) P(nrmutex); //有读者进入,互斥写操作

              V(rmutex);

              V(rwmutex); // 及时释放读写互斥信号量,允许其它读、写进程申请资源

              读数据;

              P(rmutex);

              Readcount--;

              If (readcount == 0) V(nrmutex); //所有读者退出,允许写更新

              V(rmutex);

       End

       Writerj begin // j = 1,2,….

              P(rwmutex); // 互斥后续其它读者、写者

              P(nrmutex); //如有读者正在读,等待所有读者读完

              写更新;

              V(nrmutex);   //允许后续新的第一个读者进入后互斥写操作

              V(rwmutex); //允许后续新读者及其它写者

       End

Coend


基本思想

/*---------函数声明---------*/
void Creat_Writer();    //添加一个写者
void Del_Writer();     //删除一个写者
void Creat_Reader();    //添加一个读者
void Reader_goon();     //读者进程运行函数
void R_Wakeup();     //唤醒等待读者
void Del_Reader();     //删除一个读者
void Show();     //显示运行状态 
/*===============   class   signal   ===============*/
class signal //信号量对象.
{
private:
int value;
int queue;     //用int型数据模拟等待队列.
public:
signal();
signal(int n);
int P(); //检查临界资源
int V(); //释放临界资源
int Get_Value();
int Get_Queue();
};

[C/C++]代码

#include<windows.h>   
#include<fstream>
#include<cstdlib>
#include<iostream>
using namespace std;
    
const int MaxThread=20;            

struct ThreadInfo               
{
    int num;                
    char type;                  
    double start;               
    double time;               
}thread_info[MaxThread];

HANDLE hX;    
HANDLE hWsem; 
HANDLE thread[MaxThread]; 
int readcount; 
double totaltime; 

void WRITEUNIT(int iProcess)
{
        printf("Thread %d begins to write.\n",iProcess);
        Sleep((DWORD)(thread_info[iProcess-1].time*1000));
        printf("End of thread %d  for writing.\n",iProcess);

}

void READUNIT(int iProcess)
{
        printf("Thread %d begins to read.\n",iProcess);
        Sleep((DWORD)(thread_info[iProcess-1].time*1000));
        printf("End of thread %d  for reading.\n",iProcess);
}

DWORD   WINAPI   reader(LPVOID   lpVoid)
{
    int iProcess   =   *(int*)lpVoid;
    Sleep((DWORD)(thread_info[iProcess-1].start*1000));
    DWORD wait_for=WaitForSingleObject(hX,INFINITE);
        printf("Thread %d requres reading.\n",iProcess);
        readcount++;
        if(readcount==1)WaitForSingleObject(hWsem,INFINITE);
    ReleaseMutex(hX);
        READUNIT(iProcess);
    wait_for=WaitForSingleObject(hX,INFINITE);
        readcount--;
        if(readcount==0)
        ReleaseSemaphore(hWsem,1,0);
    ReleaseMutex(hX);
    return iProcess;
}

DWORD   WINAPI   writer(LPVOID   lpVoid)
{
    int iProcess   =   *(int*)lpVoid;
    Sleep((DWORD)(thread_info[iProcess-1].start*1000));
    printf("Thread %d requres writing.\n",iProcess);
    DWORD wait_for=WaitForSingleObject(hWsem,INFINITE);
    WRITEUNIT(iProcess);
    ReleaseSemaphore(hWsem,1,0);
    return iProcess;
}
    
int main()
{
    int threadNum;
    int threadcount;
    ifstream file;

    hX=CreateMutex(NULL, FALSE, NULL);
    hWsem=CreateSemaphore(NULL,1,1,NULL);

    //???????????????????
    readcount=0;
    threadcount=0;
    totaltime=0;
    file.open("thread.dat",ios::in);
    if(file==0)
    {
        printf("File Open Error.\n");
        return 0;
    }
    while(file>>threadNum)
    {
        thread_info[threadNum-1].num=threadNum;
        file>>thread_info[threadNum-1].type;
        file>>thread_info[threadNum-1].start;
        file>>thread_info[threadNum-1].time;
        totaltime+=thread_info[threadNum-1].time;
        switch(thread_info[threadNum-1].type)
        {
          case 'W':
              printf("Creating Thread %d  for writing.\n",thread_info[threadNum-1].num);
              thread[threadNum-1]   =   CreateThread(NULL,   0,writer,   &thread_info[threadNum-1].num,0,0); 
              break;
          case 'R':
              printf("Creating Thread %d  for reading.\n",thread_info[threadNum-1].num);
              thread[threadNum-1]   =   CreateThread(NULL,   0,reader,   &thread_info[threadNum-1].num,0,0); 
              break;
      }
        threadcount++;
    }
    file.close();

    Sleep((DWORD)(totaltime*1000));
    return 1;
}

较常见的写法

semaphore fmutex = 1 , rdcntmutex = 1 ;
// fmutex --> access to file; rdcntmutex --> access to readcount 
int readcount = 0 ;
void reader()
{
     while ( 1 )
    {
        P(rdcntmutex);
         if ( readcount==0)
           P(fmutex);
        readcount = readcount + 1 ;
        V(rdcntmutex);
         // Do read operation   
        P(rdcntmutex);
        readcount = readcount - 1 ;
         if ( readcount==0)
           V(fmutex);
        V(rdcntmutex);
    }
}
void writer()
{
     while ( 1 )
    {
        P(fmutex);
         // Do write operation  
        V(fmutex);
    }
}

高手写法

semaphore fmutex = 1 , rdcntmutex = 1 , wtcntmutex = 1 , queue = 1 ;
// fmutex --> access to file; rdcntmutex --> access to readcount
// wtcntmutex --> access to writecount 
int readcount = 0 ,writecount = 0 ;
void reader()
{
     while ( 1 )
    {
        P(queue);//申请队列信号
        P(rdcntmutex);//修改readcount,互斥
         if ( readcount==0)
            P(fmutex);//access to file 互斥
        readcount = readcount + 1 ;
        V(rdcntmutex);//释放
        V(queue);//释放
         // Do read operation  
        P(rdcntmutex);
        readcount = readcount - 1 ;
         if ( readcount==0)
            V(fmutex);
        V(rdcntmutex);
    }
}
void writer()
{
     while ( 1 )
    {
        P(wtcntmutex);
         if ( writecount==0)
            P(queue);
        writecount = writecount + 1 ;
        V(wtcntmutex);
        P(fmutex);
         // Do write operation  
        V(fmutex);
        P(wtcntmutex);
        writecount = writecount - 1 ;
         if ( writecount==0)
            V(queue);
        V(wtcntmutex);
    }
}


(原文链接: http://www.oschina.net/code/snippet_180916_7505

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值