读者写者问题模拟实现-读者优先 写者优先

主要特点:

  • 输出有纵坐标,同一个线程的请求,开始,结束的表示符在同一列上,不同的不在同一列
  • 输出控制台加锁,防止输出的时候被别的线程打断,导致错位
  • 四段锁实现读者写者模拟问题,使用了两种库函数锁
  • 线程初始化自动获取存放在程序里面的有效线程个数

可以改进的方向:

  • 这个线程的初始化是在程序里面写死的,没有在控制台里面输入,我主要是感觉每次都输入挺麻烦的,而且数据太少,也不能体现读者写者优先的效果,数据太少有片面性,一开始改这个程序的时候,就是数据太少没看出来写者优先的锁加的不对。所以可以在保留数据加载的情况下,通过控制台可以改变数据或者新增数据,这样可以考虑预先设定好的数据是在程序里面还是说在文本文件里面。
  • 虽然使用了纵坐标输出,感觉起来更能明显的看出来运行顺序,但实际上,如果是两个线程在同时发起请求,这还是会不再一行上(同一行应该是一个时间),这个要编程实现呢就可能比较麻烦了,应该需要在输出的时候交给另外一个线程进行控制,这样可以在一行上输出两小段或更多段文字。我就这一个思路,供后来者参考吧。
  • 再就是,毕竟是写者优先和读者优先算法的模拟实现,比较一下两个算法的时间复杂度应该还是挺有意义的,这个也可以试一下,同样的数据,运行时间有什么不一样,什么样的数据在读者优先下总体性能会更高之类的,写者优先也同理。
  • 上面说了总体性能,那每个线程的执行时间/(结束时间-开始时间)这个参数呢,这也是一个很重要的进程调度参数。
  • 这里只实现了读者写者优先,还有一个经典算法是公平竞争。
  • 还有就是优先级抢占的问题,有没有紧急任务要紧急占用线程使用权。

实际的操作系统实现需要考虑很多内容,这是我在做这次课设考虑到的一些方面,我在原先的代码上改进了一部分,但没能将上述问题都进行实现,特以记录。如果有大佬把上面的问题实现一部分或者全部,希望能够在评论区留言,让我拜读一下代码。

上代码,运行环境是DEV-C++ 5.9.2。

#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <fstream>
#include <io.h>
#include <string.h>
#include <stdio.h>
using namespace std;
#define READER 'R'
#define WRITER 'W'
#define MAX_THREAD_NUM 32  //最大线程数目
CRITICAL_SECTION RP_Write; //临界区
CRITICAL_SECTION WP_Write; //写者优先临界区 
CRITICAL_SECTION PR_right; //写者优先控制读者锁 
CRITICAL_SECTION P_OUT;    //输出临界区

#define INTE_PER_SEC 100  //每秒时钟中断数目
#define MAX_FILE_NUM 32   //最大数据文件数目
#define MAX_STR_LEN 32    //字符串长度
int readcount=0;          //读者数目
int writecount=0;         //写者数目
struct ThreadInfo
{	int serial;           //线程序号
	char entity;          //线程类别
	double delay;         //线程开始时间
	double persist;       //线程读写持续时间
};
//创建 MAX_THREAD_NUM个线程数组,赋有初值不为0的是有效线程 
ThreadInfo  thread_info[MAX_THREAD_NUM]={
{1,'R',2,4},
{2,'W',3,4},
{3,'R',4,6},
{4,'R',6,4},
{5,'W',7,2},
{6,'W',8,6},
{7,'R',9,5},
{8,'R',10,3},
{9,'R',11,4},
{10,'W',12,4}
};
//读者优先处理函数
void ReaderPriority();   
void RP_ReaderThread(void *p);
void RP_WriterThread(void *p);
//写者优先处理函数
void WriterPriority();  
void WP_ReaderThread(void *p);
void WP_WriterThread(void *p);
//控制台输出处理函数,互斥地输出,防止输出过程被打断 
//用不同函数名表明做的是什么操作 
void Reader_request(int m_ID);
void Reader_start(int m_ID); 
void Reader_finish(int m_ID);
void Writer_request(int m_ID);
void Writer_start(int m_ID); 
void Writer_finish(int m_ID);
//获取有效的线程数目 
int sizeof_m();
int tread_num = sizeof_m();

int main()
{
	//输出一下目前待运行的线程的详细信息 
    printf("序号  读者或写者    开始时间    持续时间\n");  
	for(int i=0;i<tread_num;i++)
	{	printf(" %d\t  %c\t    %f\t%f\n",
        thread_info[i].serial,thread_info[i].entity,thread_info[i].delay,thread_info[i].persist);
    }
    InitializeCriticalSection(&P_OUT);     //初始化输出临界区
	//分别运行读者写者优先算法,方便比较 
	ReaderPriority();//读者优先
    WriterPriority();//写者优先
    
	//退出程序 
	system("pause");
	return 0;
}
//读者优先处理函数
void ReaderPriority()
{
	DWORD n_thread=tread_num;   //线程数目
	DWORD thread_ID;            //线程ID
	DWORD wait_for_all;         //等待所有线程结束
	HANDLE rmutex;	            //使读者互斥访问readcount
	//创建信号量remutex,不设定安全相关属性,不占有互斥量 
	rmutex=CreateMutex(NULL,FALSE,"mutex_for_readcount"); 
	HANDLE h_Thread[MAX_THREAD_NUM];
	readcount=0;                //初始化readcount
	InitializeCriticalSection(&RP_Write);  //初始化读者临界区
	
	printf("读者优先:(纵坐标为执行顺序)\n");
	for (int i=0;i<(int)(n_thread);i++)
	{
		if (thread_info[i].entity==READER || thread_info[i].entity=='r')
			//如果是读者线程,创建读者线程
			//不设置安全属性,分配0字节线程堆栈,指向读者线程函数地址
			//给读者线程的参数,立即执行当前线程,把新创建的线程编号给thread_ID
			h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_ReaderThread),&thread_info[i],0,&thread_ID);
		else
			//如果不是,创建写者线程
			//不设置安全属性,分配0字节线程堆栈,指向写者线程函数地址
			//给读者线程的参数,立即执行当前线程,把新创建的线程编号给thread_ID
			h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RP_WriterThread),&thread_info[i],0,&thread_ID);
	}
	//等待所有线程结束
	wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);
	printf("所有操作完成\n\n");
}
//读者优先-----读者线程
void RP_ReaderThread(void *p)
{	
	int m_ID;           //线程序号
	DWORD m_delay;      //准备延迟时间
	DWORD m_persist;    //读文件持续时间
	m_ID=((ThreadInfo *)(p))->serial;  //获取线程序号 
	m_delay=(DWORD)(((ThreadInfo *)(p))->delay*INTE_PER_SEC);     //设置准备等待时间 
	m_persist=(DWORD)(((ThreadInfo *)(p))->persist*INTE_PER_SEC); //设置读持续时间 

    HANDLE rmutex;      //使读者互斥访问readcount
	rmutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount"); //开启rmutex 
	DWORD wait_for_mutex;  //等待互斥变量所有权

	Sleep(m_delay);        //准备等待延迟 
	Reader_request(m_ID);  //读者请求输出 
	
	//P(rmutex)
	wait_for_mutex=WaitForSingleObject(rmutex,-1); 
	readcount++;           //读者数目加1
	if (readcount==1)
		//读进程与写进程互斥,如果这是第一个读者,进入临界区,开始执行 P(RP_Write);
		EnterCriticalSection(&RP_Write);  
	ReleaseMutex(rmutex); 
	//V(rmutex)
	
	Reader_start(m_ID);    //读者正在读输出 
	Sleep(m_persist);      //读持续延迟 
	Reader_finish(m_ID);   //读者完成读输出 
	
	//P(rmutex)
	wait_for_mutex=WaitForSingleObject(rmutex,-1);  
	readcount--;           //读者数目减1
	if (readcount==0)
		//读进程与写进程互斥,如果这是最后一个读者,则其释放临界区V(RP_Write);
		LeaveCriticalSection(&RP_Write); 
	ReleaseMutex(rmutex); 
	//V(rmutex)
}
//读者优先-----写者线程
void RP_WriterThread(void *p)
{
	DWORD m_delay;        //延迟时间
	DWORD m_persist;      //读文件持续时间
	int m_ID;             //线程序号
	m_ID=((ThreadInfo *)(p))->serial;  //获取线程序号 
	m_delay=(DWORD)(((ThreadInfo *)(p))->delay*INTE_PER_SEC);     //设置准备等待时间 
	m_persist=(DWORD)(((ThreadInfo *)(p))->persist*INTE_PER_SEC); //设置写持续时间

	Sleep(m_delay);       //准备等待延迟
	Writer_request(m_ID); //写者写请求输出
	 
	//进入临界区  P(RP_Write)
	EnterCriticalSection(&RP_Write);
	Writer_start(m_ID);    //写者开始写输出 
	Sleep(m_persist);      //写持续延迟 
	Writer_finish(m_ID);   //写者写完成输出 
	LeaveCriticalSection(&RP_Write); 
	//退出后,离开临界区 V(RP_Write)
}
//写者优先处理函数
void WriterPriority(){
	DWORD n_thread=tread_num;     //线程数目
	DWORD thread_ID;              //线程ID
	DWORD wait_for_all;           //等待所有线程结束
	HANDLE r_Mutex;               //使读者互斥访问readcount
	HANDLE w_Mutex;               //使写者互斥访问writecount
	HANDLE wp_Mutex;              //给以写者优先权的互斥变量
	r_Mutex=CreateMutex(NULL,FALSE,"mutex_for_readcount");       //读互斥量创建 
	w_Mutex=CreateMutex(NULL,FALSE,"mutex_for_writecount");      //写互斥量创建 
	wp_Mutex=CreateMutex(NULL,FALSE,"mutex_for_writerpriority"); //写优先互斥量创建 
	HANDLE h_Thread[MAX_THREAD_NUM];
	readcount=0;      //初始化readcount
	writecount=0;     //初始化writecount
	InitializeCriticalSection(&WP_Write);  //初始化临界区
	InitializeCriticalSection(&PR_right);  //初始化临界区
	printf("写者优先:(纵坐标为执行顺序)\n");
	for (int i=0;i<(int)(n_thread);i++)
	{
		if (thread_info[i].entity==READER || thread_info[i].entity=='r')
			//如果是读者线程,创建读者线程
			//不设置安全属性,分配0字节线程堆栈,指向读者线程函数地址
			//给读者线程的参数,立即执行当前线程,把新创建的线程编号给thread_ID
            h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(WP_ReaderThread),&thread_info[i],0,&thread_ID);
		else
			//如果不是,创建写者线程
			//不设置安全属性,分配0字节线程堆栈,指向写者线程函数地址
			//给读者线程的参数,立即执行当前线程,把新创建的线程编号给thread_ID
            h_Thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(WP_WriterThread),&thread_info[i],0,&thread_ID);
	}
	//等待所有线程结束
	wait_for_all=WaitForMultipleObjects(n_thread,h_Thread,TRUE,-1);
	printf("所有操作完成\n");
}

//写者优先-----读者线程
void WP_ReaderThread(void *p){	
	DWORD m_delay;        //准备延迟时间
	DWORD m_persist;      //读文件持续时间
	int m_ID;             //线程序号
	m_ID=((ThreadInfo *)(p))->serial;                               //获取线程序号 
	m_delay=(DWORD)(((ThreadInfo *)(p))->delay*INTE_PER_SEC);       //设置准备等待时间  
	m_persist=(DWORD)(((ThreadInfo *)(p))->persist*INTE_PER_SEC);   //设置读持续时间 

	HANDLE rmutex;       //使读者互斥访问readcount    
	rmutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_readcount"); //开启rmutex
	DWORD wait_for_rmutex;   //等待互斥变量所有权
	DWORD wait_for_right;  //等待互斥变量所有权

	Sleep(m_delay);       //准备等待延迟	
	Reader_request(m_ID); //读者请求输出 
	
	//P(PR_right)
	EnterCriticalSection(&PR_right); 
	//P(rmutex)
	wait_for_rmutex=WaitForSingleObject(rmutex,-1);   
	if (readcount==0)
		EnterCriticalSection(&WP_Write);   //如果这是第一个读者,写者优先进入临界区 P(WP_Write)
	readcount++;          //读者数目加1
	ReleaseMutex(rmutex);
	//V(rmutex)
	LeaveCriticalSection(&PR_right);  
	//V(PR_right)
	
	Reader_start(m_ID);  //读者正在读输出 
	Sleep(m_persist);    //读持续延迟 
	Reader_finish(m_ID); //读者完成读输出 
	
	//P(rmutex)
	wait_for_rmutex=WaitForSingleObject(rmutex,-1);
	readcount--;         //读者数目减1
	if (readcount==0)
		LeaveCriticalSection(&WP_Write);   //如果读者都退出,写者进入临界区V(WP_Write)
	ReleaseMutex(rmutex);
	//V(rmutex)
}
//写者优先-----写者线程
void WP_WriterThread(void *p){
	DWORD m_delay;         //延迟时间
	DWORD m_persist;       //读文件持续时间
	int m_ID;              //线程序号
	m_ID=((ThreadInfo *)(p))->serial;                              //获取线程序号 
	m_delay=(DWORD)(((ThreadInfo *)(p))->delay*INTE_PER_SEC);      //设置准备等待时间 
	m_persist=(DWORD)(((ThreadInfo *)(p))->persist*INTE_PER_SEC);  //设置读持续时间 

	HANDLE writerm;      //给以写者优先权的互斥变量
	HANDLE wmutex;       //使写者互斥访问writecount
	writerm=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"mutex_for_writerpriority");  //开启writerm
	DWORD wait_for_writerm; //等待互斥变量所有权

	Sleep(m_delay);       //准备等待延迟	
	Writer_request(m_ID); //写者写请求输出 
	
	//P(writerm)
	wait_for_writerm=WaitForSingleObject(writerm,-1); 
	writecount++;         //写者数目加1
	if (writecount==1)
		EnterCriticalSection(&PR_right);     //如果是第一个写者,进入临界区P(PR_right)
	ReleaseMutex(writerm);
	//V(writerm)
	
	//P(WP_Write)
	EnterCriticalSection(&WP_Write);
	Writer_start(m_ID);   //写者写完成输出 
	Sleep(m_persist);     //写持续延迟 
	Writer_finish(m_ID);  //写者写完成输出 
	LeaveCriticalSection(&WP_Write);
	//V(WP_Write)
	
	//P(writerm)
	wait_for_writerm=WaitForSingleObject(writerm,-1); 
	writecount--;         //写者数目减1
	if (writecount==0)
    	LeaveCriticalSection(&PR_right);   //如果是最后一个写者退出,离开临界区V(PR_right)
	ReleaseMutex(writerm);
	//V(writerm)
}
//读者请求输出函数 
void Reader_request(int m_ID)
{
	//P(P_OUT) 输出互斥 
	EnterCriticalSection(&P_OUT);
	for(int i=1;i<m_ID;i++)
	printf("           ");
	printf("读者%d读请求\n",m_ID);
	LeaveCriticalSection(&P_OUT);
	//V(P_OUT)	
}
//读者开始输出函数 
void Reader_start(int m_ID)
{
	//P(P_OUT) 输出互斥 
	EnterCriticalSection(&P_OUT);	
    for(int j=1;j<m_ID;j++)//读文件
	printf("           ");
	printf("读者%d开始读\n",m_ID);
	LeaveCriticalSection(&P_OUT);
	//V(P_OUT) 
}
//读者结束输出函数 
void Reader_finish(int m_ID)
{
	//P(P_OUT) 输出互斥 
	EnterCriticalSection(&P_OUT);
    for(int k=1;k<m_ID;k++)//退出线程
	printf("           ");
	printf("读者%d完成读\n\n",m_ID);
	LeaveCriticalSection(&P_OUT);
	//V(P_OUT)
}
//写者请求输出函数 
void Writer_request(int m_ID)
{
	//P(P_OUT) 输出互斥 
	EnterCriticalSection(&P_OUT);
	for(int i=1;i<m_ID;i++)
	printf("           ");
	printf("写者%d写请求\n",m_ID);
	LeaveCriticalSection(&P_OUT);
	//V(P_OUT)	
}
//写者开始输出函数 
void Writer_start(int m_ID)
{
	//P(P_OUT) 输出互斥 
	EnterCriticalSection(&P_OUT);
    for(int l=1;l<m_ID;l++)	//写文件
	printf("           ");
	printf("写者%d开始写\n",m_ID);
	LeaveCriticalSection(&P_OUT);
	//V(P_OUT)
}
//写者结束输出函数 
void Writer_finish(int m_ID)
{
	//P(P_OUT) 输出互斥 
	EnterCriticalSection(&P_OUT);
    for(int t=1;t<m_ID;t++)	//退出线程
	printf("           ");
	printf("写者%d完成写\n",m_ID);
	LeaveCriticalSection(&P_OUT);
	//V(P_OUT)
}
//获取当前初始化的有效线程个数  
int sizeof_m()
{	
	for(int i=0;i<MAX_THREAD_NUM;i++)
	{
		if(thread_info[i].serial==0)
		return i;
	}
	return MAX_THREAD_NUM;
}

在这里插入图片描述在这里插入图片描述
附上两张我画的流程图:
读者优先:
在这里插入图片描述
写者优先:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值