读者写者问题(读者优先)

一、读者写者问题定义

存在一个多个进程共享的数据区,该数据区可以是一个文件或一块内存空间,甚至可以是一组寄存器:有些进程(reader)只读取这个数据区中的数据,有些进程(writer)只往数据区中写数据。
此外,还必须满足以下条件

1、任意数量的读进程可同时读这个文件。
2、一次只能有一个写进程可以写文件。
3、若存在一个写进程正在写文件,则禁止任何读进程读文件。
4、若存在读进程正在读文件,则任何写进程需等待,直至当前的读进程全部执行读操作完毕!

也就是说,读进程不需要排斥其他读进程,而写进程需要排斥其他所有进程。

二、读者优先(C++代码)

#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>//sleep函数
using namespace std;
//信号量的数据类型为结构sem_t,它本质上是一个长整型的数
sem_t RW, Mutex;//信号量 
int readCounts = 0;

typedef struct DATA{
    
    
    int id;
    int set_upTime;//启动时间 
    int exeTime;//执行时间 
}data;

/* 测试例子 
1 R 2 6
2 W 3 5
3 R 6 3
4 R 4 6
5 W 3 6
*/ 

//读者
void* Reader(void* tem) 
{
    
    
    int id = ((data*)tem)->id;
    int set_upTime = ((struct DATA*)tem)->set_upTime;
    int exeTime = ((data*)tem)->exeTime;
    sleep(set_upTime);
    
    printf("线程 %d:           等待“读”\n", id);
    //用于确保readCounts被正确更新 
    sem_wait(&Mutex);//P//用来阻塞当前线程直到信号量mutex的值大于0, 
					 //解除阻塞后将mutex的值减一,表明公共资源经使用后减少。 
    readCounts++;
	if(readCounts == 1)
        sem_wait(&RW);//等待读写权,且有优先使用权(较于写者)情况是当队列中有读者写者
	//且读者排在写者前面,那么后来的读者可以排在最后一个等待读的后面/第一个等待写的前面 
    sem_post(&Mutex);//V 
	
    printf("线程 %d: 开始“读”\n", id);
    sleep(exeTime);
    printf("线程 %d:                    “读”结束\n", id);
	
	sem_wait(&Mutex);
    readCounts--;
    if(readCounts == 0)
        sem_post(&RW);//解锁 
    sem_post(&Mutex);
    
    pthread_exit(0);
}

//写者
void* writer(void* tem) 
{
    
    
    int id = ((data*)tem)->id;
    int exeTime = ((DATA*)tem)->exeTime;
    int set_upTime = ((struct DATA*)tem)->set_upTime;

    sleep(set_upTime);
    printf("线程 %d:           等待“写”\n", id);
    
    sem_wait(&RW);//P 等待读写权 
    printf("线程 %d: 开始“写”\n", id);
    sleep(exeTime);
    printf("线程 %d:                    “写”结束\n", id);
    sem_post(&RW);//释放读写权 
    
    pthread_exit(0);
}
int main() {
    
    
    int id = 0;
    pthread_t tid; //用于声明线程ID
    pthread_attr_t attr; //线程 属性 
    //pthread_attr_init(&attr);//初始化一个线程对象 
    sem_init(&Mutex, 0, 1);//用来初始化一个信号量
    //第一个参数: 信号量名
    //第二个参数: 表示允许几个进程共享该信号量,0表示用于进程内的多线程共享
    //第三个参数: 表示可用的资源的数目
    sem_init(&RW, 0, 1);
    cout<<"请依次输入以下四项信息"<<endl;
    cout<<"线程ID"<<" | "<<"身份"<<" | "<<"启动时间"<<" | "<<"执行时间"<<endl<<endl; 
    while(scanf("%d", &id) != EOF) 
	{
    
    
        char role;      //读者"R" or 写者"W" 
        int set_upTime;     //启动时间
        int exeTime;   //运行时间

        scanf("%c%d%d", &role, &set_upTime, &exeTime);
        //data* d = ( data*)malloc(sizeof( data));
		data* d = new DATA;//本句和上一句效果是一样的
        d->id = id;
        d->set_upTime = set_upTime;
        d->exeTime = exeTime;

        if(role == 'R'||role == 'r') {
    
    
            printf("创建线程 %d: 读者\n\n", id);//Reader Create the %d thread
            pthread_create(&tid, &attr, Reader, d);//创建线程 
            //第一个参数为指向线程 标识符的 指针
            //第二个参数用来设置线程属性
			//第三个参数是线程运行函数的起始地址
			//最后一个参数是运行函数的参数
        }
        else if(role == 'W'||role == 'w') {
    
    
            printf("创建线程 %d: 写者\n\n", id);//Writer
            pthread_create(&tid, &attr, writer, d);
        }
        
    	//cout<<"Read/Write operations all execute over!"<<endl;
    }
    //信号量销毁
    sem_destroy(&Mutex);
    sem_destroy(&RW);
    return 0;
}

三、代码说明

写进程比较简单,信号量RW用于实施互斥,只要一个写进程正在访问共享数据区时。其他写进程和读进程都不能访问它。
读进程也使用RW实施互斥,但为了允许多个读进程在没有读进程正在读时,第一个试图读的读进程需要在RW上等待。当至少已有一个读进程正在读时,随后的读进程无须等待,可以直接进入,全局变量readCounts用于记录读进程的数量,信号量Mutex用于确保readCounts被正确地更新。

此内容为操作系统书中知识,比较简单、易实现,适于学习、理解信号量原理。
转载需说明!

猜你喜欢

转载自blog.csdn.net/weixin_47700137/article/details/119709928