课程设计设计题目 读者-写者问题

[设计目的]

1. 学习并实现进程同步机制;

2. 理解互斥(Mutex)和信号量(Semaphore)的使用*;

3. 掌握解决并发访问问题的方法。

[设计要求]

在操作系统中,需要设计一个算法来控制对共享资源的访问,确保数据的一致性和完整性。

在操作系统中,需要考虑效率和公平性,避免饥饿和死锁。

设计思路:

读者-写者问题是一个非常经典的问题,基本上每个学校老师在讲课操作系统这门课时都会详细讲解,这里我就不赘述了,但是我们要理解其中的三个原则:“读读共享,读写互斥,写写互斥”

然后还有三种情况,读者优先,写者优先,读者写者公平竞争

[设计思想及内容]

设计思想通常基于使用互斥锁来保护资源,以及使用信号量来控制读者和写者的数量。可以采用以下策略:

1使用一个互斥锁来保护资源的读写操作。

2使用两个信号量,一个用于控制读者的数量(读者信号量),另一个用于控制写者(写者信号量)。

[数据结构设计]

sem_t wmutex: 写者互斥信号量,用于保证写者在写入时的互斥访问。

sem_t rmutex: 读者互斥信号量,用于同步读者对共享资源的访问。

sem_t mutex1: 用于保护共享资源,确保一次只有一个读者或写者可以访问资源(在写者优先和公平竞争的代码中使用)。

sem_t num: 用于控制对共享资源的访问,特别是实现写者优先策略(在写者优先和公平竞争的代码中使用)。

pthread_t writer, pthread_t reader[N]: 存储创建的线程标识符,用于后续的线程同步操作。

信号量 sem_t 被用作互斥锁的功能来保护共享资源。

信号量的 sem_wait 和 sem_post 操作隐含地实现了条件变量的功能,用于线程间的同步。

[程序源码]

readfirst 读者优先
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
 //用于记录当前正在读取的读者数量
#define N 5
//用于记录当前正在读取的读者数量
int count=0; 
//控制读者和写者访问次数
int a = 5;
int b = 5;
int r[N]={0,1,2,3,4};
sem_t wmutex;// 写者互斥信号量
sem_t rmutex;//读者互斥信号量
 
 //产生延时函数
void delay()
{
sleep(1);
}
 
void Reader(void *arg)
{
	int i=*(int *)arg;
	while(a>0)
	{
    		a--;
    		delay();
//等待读者互斥信号量,确保对count的原子操作
sem_wait(&rmutex); 
        	if(count==0)//如果没有其他读者,等待写者互斥信号量
        	    sem_wait(&wmutex);
        	count++;//增加读者数量
        	sem_post(&rmutex);
	
        	printf("Reader%d is reading!\n",i);
        	printf("Reader%d reads end!\n",i);
        	//再次等待读者互斥信号量,准备减少读者数量
        	sem_wait(&rmutex);
        	count--;//减少读者数量
        	if(count==0)//如果没有其他读者,释放写者互斥信号量
        	    sem_post(&wmutex);
        	sem_post(&rmutex);
    	}	
}
 
void Writer()
{
	while(b>0)
    	{
    		b--;
    		delay();
        	sem_wait(&wmutex);//等待写者互斥信号量
    		
    		printf("writer is writing!\n");
        	printf("writer writes end!\n");
    		
        	sem_post(&wmutex);//释放写者互斥信号量
    	}
}
 
int main()
{
	int i;
	pthread_t writer,reader[N];
	//初始化互斥信号量
	sem_init(&wmutex,0,1);//互斥锁初始化
	sem_init(&rmutex,0,1);
	
	for(i=0;i<5;i++)//创建读者线程
	{
		pthread_create(&reader[i],NULL,(void *)Reader,&r[i]);
	} 
	//创建写者进程
	pthread_create(&writer,NULL,(void *)Writer,NULL);
	//等待写者进程结束
	pthread_join(writer,NULL);//线程等待 
	//销毁互斥信号量
	sem_destroy(&rmutex);   //互斥锁的销毁
	sem_destroy(&wmutex);   
	return 0;
}
Writefirst 写者优先
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdlib.h>
#include <unistd.h>

#define MAX_READERS 5
#define MAX_WRITERS 2

// 用于记录当前正在读取的读者数量
int reader_count = 0;
// 用于记录是否有写者正在等待
int writer_waiting = 0;
// 用于记录是否有写者正在写入
int writer_active = 0;

// 函数声明
void lock();
void unlock();
void writer_lock();
void writer_unlock();

// 信号量定义
sem_t mutex;
sem_t readers;
sem_t writers;
sem_t write_resource;

int main() {
    pthread_t readers[MAX_READERS], writers[MAX_WRITERS];

    // 初始化信号量
sem_init(&mutex, 0, 1);           
// 互斥锁,用于保护共享资源
sem_init(&readers, 0, MAX_READERS); 
// 读者信号量,最大读者数为MAX_READERS
sem_init(&writers, 0, MAX_WRITERS); 
// 写者信号量,最大写者数为MAX_WRITERS
sem_init(&write_resource, 0, 1);   
// 写者资源锁,确保一次只有一个写者访问资源

    // 创建读者线程
    for (int i = 0; i < MAX_READERS; ++i) {
        pthread_create(&readers[i], NULL, (void *(*)(void *))reader, NULL);
    }

    // 创建写者线程
    for (int i = 0; i < MAX_WRITERS; ++i) {
        pthread_create(&writers[i], NULL, (void *(*)(void *))writer, NULL);
    }

    // 等待线程结束
    for (int i = 0; i < MAX_READERS; ++i) {
        pthread_join(readers[i], NULL);
    }
    for (int i = 0; i < MAX_WRITERS; ++i) {
        pthread_join(writers[i], NULL);
    }

    // 销毁信号量
    sem_destroy(&mutex);
    sem_destroy(&readers);
    sem_destroy(&writers);
    sem_destroy(&write_resource);

    return 0;
}

// 读者线程函数
void* reader(void *args) {
    while (1) {
        // 读者进入
        sem_wait(&mutex);
        reader_count++;
        if (reader_count == 1) {
            // 如果是第一个读者,需要获取读资源锁
            sem_wait(&readers);
        }
        sem_post(&mutex);

        // 模拟读取操作
        printf("Reader is reading.\n");
        sleep(1);

        // 读者退出
        sem_wait(&mutex);
        reader_count--;
        if (reader_count == 0) {
 // 如果是最后一个读者,需要释放读资源锁并检查是否有写者等待
            sem_post(&readers);
            if (writer_waiting) {
                writer_lock();
                writer_active = 1;
                writer_unlock();
            }
        }
        sem_post(&mutex);
    }
    return NULL;
}

// 写者线程函数
void* writer(void *args) {
    while (1) {
        // 写者进入等待区
        writer_lock();
        writer_waiting = 1;

        // 如果写者正在写入或有其他写者在等待,则等待
        while (writer_active || reader_count > 0) {
            sem_wait(&write_resource);
        }

        // 写者获得资源,开始写入
        writer_active = 1;
        writer_waiting = 0;
        writer_unlock();

        // 模拟写入操作
        printf("Writer is writing.\n");
        sleep(2);

        // 写者完成写入,释放资源
        writer_lock();
        writer_active = 0;
        if (writer_waiting) {
            sem_post(&write_resource);
        }
        writer_unlock();
    }
    return NULL;
}

// 锁定函数,用于读者和写者的互斥操作
void lock() {
    sem_wait(&mutex);
}

// 解锁函数
void unlock() {
    sem_post(&mutex);
}

// 写者锁定函数,用于写者之间的互斥和等待
void writer_lock() {
    sem_wait(&writers);
}

// 写者解锁函数
void writer_unlock() {
    sem_post(&writers);
}
Readwrite 读者写者公平竞争
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
 
#define N 5
 
int readcount=0,writecount=0,a=5,b=2;
int r[N]={0,1,2,3,4};
int w[N]={0,1};

sem_t wmutex; // 写者互斥信号量,用于控制写者之间的互斥
sem_t rmutex; // 读者互斥信号量,用于控制读者之间的互斥
// 共享资源互斥信号量,用于控制读者和写者对共享资源的互斥
sem_t mutex1;
sem_t num; // 用于控制对共享资源的访问,实现写者优先

 
void delay()
{
	sleep(1);
}
 
//读者线程函数
void Reader(void *arg)
{
	int i=*(int *)arg;
	while(a>0)
	{
    		a--;//减少读者访问次数
    		delay();//延迟
    		
		//等待读者互斥信号量,确保对count的原子操作 
    	sem_wait(&num);//在无写者进程时进入
      sem_wait(&rmutex);//与其他读者进程互斥的访问readcount

        	if(readcount==0)
        		sem_wait(&mutex1);//与写者进程互斥的访问共享文件
        	readcount++;
        	sem_post(&rmutex);
        	sem_post(&num); 
	
		//reader
        	printf("Reader%d is reading!\n",i);
        	printf("Reader%d reads end!\n",i);
        	
        	//退出文件后的处理
        	sem_wait(&rmutex);
        	readcount--;
        	if(readcount==0)
        		sem_post(&mutex1);
        	sem_post(&rmutex);
    	}	
}
 
void Writer(void *arg)
{
	int i=*(int *)arg;
	while(b>0)
    	{
    		b--;
    		delay();
    		
    		//进入共享文件前的准备 
  sem_wait(&wmutex);//保证多个写者进程能够互斥使用writecount 
    		writecount++;
    		if(writecount==1)
    			sem_wait(&num);//用于禁止读者进程
    		sem_post(&wmutex);
    		
    		//writer
      sem_wait(&mutex1);//与其他所有进程互斥的访问共享文件
    		printf("writer%d is writing!\n",i); 
        	printf("writer%d writes end!\n",i);
    		sem_post(&mutex1);
        	
        	//退出共享文件后的处理
        	sem_wait(&wmutex);
    		writecount--;
    		if(writecount==0)
    			sem_post(&num);
    		sem_post(&wmutex);
    	}
}
 
int main()
{
	int i;
	pthread_t writer[N],reader[N];
	sem_init(&wmutex,0,1);//互斥锁初始化
	sem_init(&rmutex,0,1);
	sem_init(&mutex1,0,1);	
	sem_init(&num,0,1);
	
	for(i=0;i<5;i++)//创建线程 
	{
		pthread_create(&reader[i],NULL,(void *)Reader,&r[i]);
	} 
	
	for(i=0;i<2;i++)//创建线程 
	{
		pthread_create(&writer[i],NULL,(void *)Writer,&w[i]);
	}
	
	for(i=0;i<2;i++)//等待线程
	{
		pthread_join(writer[i],NULL);
	}
	
	for(i=0;i<5;i++)//等待线程
	{
		pthread_join(reader[i],NULL);
	}	
	
	sem_destroy(&rmutex);   //互斥锁的销毁
	sem_destroy(&wmutex);   
	sem_destroy(&mutex1);
	sem_destroy(&num);
	
	return 0;
} 

[设计实现展示(可附截图说明)]

读者优先:

写者优先

读者写者公平竞争

[课程设计出现问题及解决方法]

出现的问题:

在写者优先时,老是会读者写者交叉显示,无法达到想要的效果

解决办法:

设置一个延时函数,每次延时1秒,即可保证顺序显示

【参考资料】

https://blog.csdn.net/william_munch/article/details/84256690

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值