操作系统 读者写者问题的实现(C++ 读者优先、写者优先)

通过信号量机制和相应的系统调用,用于线程的互斥和同步,实现读者写者问题。利用信号量机制,实现读者写者问题。

在windows 10环境下,创建一个控制台进程,此进程包含n个线程。用这n个线程来表示n个读者或写者。每个线程按照设定进行读写操作。用信号量机制分别实现读者优先和写者优先的读者写者问题。
读者和写者问题的读写操作限制(包括读者优先和写者优先):
写写互斥:即不能有两个写者同时进行写操作。
读写互斥:即不能同时有一个线程在读,而另一个线程在写。
读读允许:即可以有一个或多个读者在读。
读者优先的附加限制:如果一个读者申请进行读操作时已有另一个读者正在进行读操作,则该读者可直接开始读操作。
写者优先的附加限制:如果一个读者申请进行读操作时已有另一写者在等待访问共享资源,则该读者必须等到没有写者处于等待状态才能开始读操作。

读者优先:
如果没有写者正在操作,则读者并不需要等待,用一个整型变量readercount表示正在读的进程数目。由于只要有一个Reader进程在读,便不允许Writer进程去写,于是仅当readercount=0时,说明尚无读者进程在读,Reader进程才需要执行wait(book)操作。若该操作成功了,Reader进程便可去读,相应地,做readercount+1操作。同理,仅当Reader进程在执行了readercount减一操作后其值为0时,才须执行signal(book)操作,以便让Writer进程写操作。,每个读者开始读之前都要修改readercount,为了互斥的实现对readercount 的修改,需要一个互斥对象rc_mutex来实现互斥。
为实现Reader与Writer进程间在读或在写的互斥而设置一个互斥的信号量book,表示对资源的访问。当写者发出写的请求时,必须先得到允许。通过这种方法,可以实现读写互斥,当readcount=0时,(即第一个读者的到来时,),读者线程也必须申请。
当读者拥有所有权,写者都阻塞在信号量对象book上。当写者拥有所有权时,第一个判断完readcount==0 后,其余的读者由于等待对readcount的判断,阻塞在rc_mutex上。

写者优先:
写者优先和读者优先有相同之处,不同的地方在:一旦有一个写者到来时,应该尽快让写者进行写,如果有一个写者在等待,则新到的读者操作不能读操作,为此添加一个整型变量writercount,记录写者的数目,当writercount=0时才可以释放读者进行读操作。
为了实现对全局变量writercount的互斥访问,设置了一个互斥信号量wc_mutex,同时,读者线程要对全局变量readercount实现操作上的互斥,必须有一个互斥对象命名为。
为了实现写者优先,设置一个临界区对象read,当有写者在写或等待时,读者必须阻塞在临界区对象read上。同样,有读者读时,写者必须等待。于是,必须有一个互斥对象book来实现这个互斥。
写者的操作应该优先于读者,则信号量一直被占用着,直到没有写者的时候才会释放,即当writerCount等于1的时候,申请信号量book,其余的写者无需再次申请,但是写者是不能同时进行写操作的,则需要设置一个信号量wrt来保证每次只有一个写者进行写操作,当写者的数量writeCount等于0的时候,则证明此时没有没有读者了,释放信号量book。当readCount为1的时候,为阻止写者进行写操作,申请信号量wrt,则写者就无法进行写操作了。信号量mutex的主要用处就是避免写者同时与多个读者进行竞争,读者中信号量book比mutex先释放,则一旦有写者,写者可马上获得资源。

实现效果图:

读者写者测试文本
在这里插入图片描述
读者优先:
在这里插入图片描述
写者优先:
在这里插入图片描述

最后给出源码:

#include<iostream>
#include<string>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h> 
#include <fstream>
#include <io.h>
#include <string.h>
#include<algorithm>
#include<Windows.h> //多线程编程
#include<process.h>
using namespace std;

#define READER 'R'                   //读者
#define WRITER 'W'                   //写者
#define INTE_PER_SEC 1000            //每秒时钟中断的数目
#define MAX_THREAD_NUM 64            //最大线程数目

//变量声明初始化
int readercount = 0;//记录等待的读者数目
int writercount = 0;//记录等待的写者数目

HANDLE rc_mutex;//因为读者数量而添加的互斥信号量,用于读者优先

HANDLE rc2_mutex;//因为读者数量而添加的互斥信号量,用于写者优先
HANDLE wc_mutex;//因为写者数量而添加的互斥信号量
HANDLE book;//互斥访问信号量
HANDLE wrt;//保证每次只有一个写者进行写操作,当写者的数量writercount等于0的时候,则证明此时没有没有读者了,释放信号量book
HANDLE mutex;//避免写者同时与多个读者进行竞争,读者中信号量RWMutex比mutex3先释放,则一旦有写者,写者可马上获得资源

struct thread_info {
	int id;		      //线程序号
	char entity;      //线程类别(判断是读者线程还是写者线程)
	double delay;		 //线程延迟时间
	double lastTime;	 //线程读写操作时间
};
/*****************/
//读者优先
//进程管理-读者线程
void rp_threadReader(void *p)
{
	DWORD m_delay;                   //延迟时间
	DWORD m_persist;                 //读文件持续时间
	int m_serial;                    //线程序号
									 //从参数中获得信息
	m_serial = ((thread_info*)(p))->id;
	m_delay = (DWORD)(((thread_info*)(p))->delay *INTE_PER_SEC);
	m_persist = (DWORD)(((thread_info*)(p))->lastTime *INTE_PER_SEC);
	Sleep(m_delay);                  //延迟等待

	printf("读者进程%d申请读文件.\n", m_serial);
	//cout << "读者进程"<< m_serial<<"申请读文件." << endl;

	WaitForSingleObject(rc_mutex, -1);//对readercount互斥访问
	if (readercount == 0)WaitForSingleObject(book, -1);//第一位读者申请书
	readercount++;
	ReleaseSemaphore(rc_mutex, 1, NULL);//释放互斥信号量rc_mutex

	printf("读者进程%d开始读文件.\n", m_serial);
	Sleep(m_persist);
	printf("读者进程%d完成读文件.\n", m_serial);

	WaitForSingleObject(rc_mutex, -1);//修改readercount
	readercount--;//读者读完
	if (readercount == 0)ReleaseSemaphore(book, 1, NULL);//释放书籍,写者可写
	ReleaseSemaphore(rc_mutex, 1, NULL);//释放互斥信号量rc_mutex
}
/*****************/
//读者优先
//进程管理-写者线程
void rp_threadWriter(void *p)
{
	DWORD m_delay;                   //延迟时间
	DWORD m_persist;                 //读文件持续时间
	int m_serial;                    //线程序号
									 //从参数中获得信息
	m_serial = ((thread_info*)(p))->id;
	m_delay = (DWORD)(((thread_info*)(p))->delay *INTE_PER_SEC);
	m_persist = (DWORD)(((thread_info*)(p))->lastTime *INTE_PER_SEC);
	Sleep(m_delay);                  //延迟等待
	printf("写者进程%d申请写文件.\n", m_serial);
	WaitForSingleObject(book, INFINITE);//申请资源
	/*write is performed*/
	printf("写者进程%d开始读文件.\n", m_serial);
	Sleep(m_persist);
	printf("写者进程%d完成读文件.\n", m_serial);
	ReleaseSemaphore(book, 1, NULL);//释放资源
}
//读者优先
void ReaderPriority(char *file)
{
	DWORD n_thread = 0;           //线程数目
	DWORD thread_ID;            //线程ID
	DWORD wait_for_all;         //等待所有线程结束

								//创建信号量
	rc_mutex = CreateSemaphore(NULL, 1, 1, "mutex_for_readcount");//读者对count修改互斥信号量,初值为1,最大为1
	book = CreateSemaphore(NULL, 1, 1, NULL);//书籍互斥访问信号量,初值为1,最大值为1

	HANDLE h_Thread[MAX_THREAD_NUM];//线程句柄,线程对象的数组
	thread_info thread_info[MAX_THREAD_NUM];

	int id = 0;
	readercount = 0;               //初始化readcount
	ifstream inFile;
	inFile.open(file);
	cout << "读者优先:" << endl;
	while (inFile)
	{
		//读入每一个读者,写者的信息
		inFile >> thread_info[n_thread].id;
		inFile >> thread_info[n_thread].entity;
		inFile >> thread_info[n_thread].delay;
		inFile >> thread_info[n_thread++].lastTime;
		inFile.get();
	}
	for (int i = 0; i<(int)(n_thread); i++)
	{
		if (thread_info[i].entity == READER || thread_info[i].entity == 'r')
		{
			//创建读者进程
			h_Thread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(rp_threadReader), &thread_info[i], 0, &thread_ID);
		}
		else
		{
			//创建写线程
			h_Thread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(rp_threadWriter), &thread_info[i], 0, &thread_ID);
		}
	}
	//等待子线程结束

	//关闭句柄
	wait_for_all = WaitForMultipleObjects(n_thread, h_Thread, TRUE, -1);
	cout << endl;
	cout << "所有读者写者已经完成操作!!" << endl;
	for(int i = 0; i<(int)(n_thread); i++)
		CloseHandle(h_Thread[i]);
	CloseHandle(rc_mutex);
	CloseHandle(book);
}
/*****************/
//写者优先
//进程管理-读者线程
void wp_threadReader(void *p) {
	DWORD m_delay;                   //延迟时间
	DWORD m_persist;                 //读文件持续时间
	int m_serial;                    //线程序号
									 //从参数中获得信息
	m_serial = ((thread_info*)(p))->id;
	m_delay = (DWORD)(((thread_info*)(p))->delay *INTE_PER_SEC);
	m_persist = (DWORD)(((thread_info*)(p))->lastTime *INTE_PER_SEC);
	Sleep(m_delay);                  //延迟等待

	printf("读者进程%d申请读文件.\n", m_serial);
	WaitForSingleObject(mutex, -1);
	WaitForSingleObject(book, -1);
	WaitForSingleObject(rc2_mutex, -1);//对readercount互斥访问
	if (readercount == 0)WaitForSingleObject(wrt, -1);//第一位读者申请书,同时防止写者进行写操作
	readercount++;

	ReleaseSemaphore(rc2_mutex, 1, NULL);//释放互斥信号量rc_mutex
	ReleaseSemaphore(book, 1, NULL);//释放互斥信号量book
	ReleaseSemaphore(mutex, 1, NULL);//释放互斥信号量mutex
									 /* reading is performed */
	printf("读者进程%d开始读文件.\n", m_serial);
	Sleep(m_persist);
	printf("读者进程%d完成读文件.\n", m_serial);
	WaitForSingleObject(rc2_mutex, -1);//修改readercount
	readercount--;//读者读完
	if (readercount == 0)ReleaseSemaphore(wrt, 1, NULL);//释放资源,写者可写
	ReleaseSemaphore(rc2_mutex, 1, NULL);//释放互斥信号量rc_mutex
}
/*****************/
//写者优先
//进程管理-写者线程
void wp_threadWriter(void *p) {
	DWORD m_delay;                   //延迟时间
	DWORD m_persist;                 //读文件持续时间
	int m_serial;                    //线程序号
									 //从参数中获得信息
	m_serial = ((thread_info*)(p))->id;
	m_delay = (DWORD)(((thread_info*)(p))->delay *INTE_PER_SEC);
	m_persist = (DWORD)(((thread_info*)(p))->lastTime *INTE_PER_SEC);
	Sleep(m_delay);                  //延迟等待

	printf("写者进程%d申请写文件.\n", m_serial);
	WaitForSingleObject(wc_mutex, -1);//对writercount互斥访问
	if (writercount == 0)WaitForSingleObject(book, -1);//第一位写者申请资源
	writercount++;
	ReleaseSemaphore(wc_mutex, 1, NULL);//释放资源

	WaitForSingleObject(wrt, -1);
	/*write is performed*/
	printf("写者进程%d开始写文件.\n", m_serial);
	Sleep(m_persist);
	printf("写者进程%d完成写文件.\n", m_serial);
	ReleaseSemaphore(wrt, 1, NULL);//释放资源

	WaitForSingleObject(wc_mutex, -1);//对writercount互斥访问
	writercount--;
	if (writercount == 0)ReleaseSemaphore(book, 1, NULL);//释放资源
	ReleaseSemaphore(wc_mutex, 1, NULL);//释放资源
}
//写者优先
void WriterPriority(char *file) {
	DWORD n_thread = 0;           //线程数目
	DWORD thread_ID;            //线程ID
	DWORD wait_for_all;         //等待所有线程结束

								//创建信号量
	rc2_mutex = CreateSemaphore(NULL, 1, 1, "mutex_for_readercount");//读者对count修改互斥信号量,初值为1,最大为1
	wc_mutex = CreateSemaphore(NULL, 1, 1, "mutex_for_writercount");//写者对count修改互斥信号量,初值为1,最大为1
	wrt = CreateSemaphore(NULL, 1, 1, NULL);//
	mutex = CreateSemaphore(NULL, 1, 1, NULL);//
	book = CreateSemaphore(NULL, 1, 1, NULL);//书籍互斥访问信号量,初值为1,最大值为1

	HANDLE h_Thread[MAX_THREAD_NUM];//线程句柄,线程对象的数组
	thread_info thread_info[MAX_THREAD_NUM];

	int id = 0;
	readercount = 0;               //初始化readcount
	writercount = 0;
	ifstream inFile;
	inFile.open(file);
	cout << "写者优先:" << endl;
	while (inFile)
	{
		//读入每一个读者,写者的信息
		inFile >> thread_info[n_thread].id;
		inFile >> thread_info[n_thread].entity;
		inFile >> thread_info[n_thread].delay;
		inFile >> thread_info[n_thread++].lastTime;
		inFile.get();
	}
	for (int i = 0; i<(int)(n_thread); i++)
	{
		if (thread_info[i].entity == READER || thread_info[i].entity == 'r')
		{
			//创建读者进程
			h_Thread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(wp_threadReader), &thread_info[i], 0, &thread_ID);
		}
		else
		{
			//创建写线程
			h_Thread[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)(wp_threadWriter), &thread_info[i], 0, &thread_ID);
		}
	}
	//等待子线程结束

	//关闭句柄
	wait_for_all = WaitForMultipleObjects(n_thread, h_Thread, TRUE, -1);
	cout << endl;
	cout << "所有读者写者已经完成操作!!" << endl;
	for (int i = 0; i<(int)(n_thread); i++)
		CloseHandle(h_Thread[i]);
	CloseHandle(wc_mutex);
	CloseHandle(rc2_mutex);
	CloseHandle(book);
}
//主函数
int main()
{
	char choice;
	cout << "    欢迎进入读者写者模拟程序    " << endl;
	while (true)
	{
		//打印提示信息
		cout << "     请输入你的选择       " << endl;
		cout << "     1、读者优先" << endl;
		cout << "     2、写者优先" << endl;
		cout << "     3、退出程序" << endl;
		cout << endl;
		//如果输入信息不正确,继续输入
		do {
			choice = (char)_getch();
		} while (choice != '1'&&choice != '2'&&choice != '3');

		system("cls");
		//选择1,读者优先
		if (choice == '1')
			//ReaderPriority("thread.txt");
			ReaderPriority(const_cast<char *>("thread.txt"));
		//选择2,写者优先
		else if (choice == '2')
			WriterPriority(const_cast<char *>("thread.txt"));
		//选择3,退出
		else
			return 0;
		//结束
		printf("\nPress Any Key to Coutinue");
		_getch();
		system("cls");
	}
	return 0;
}
  • 76
    点赞
  • 486
    收藏
    觉得还不错? 一键收藏
  • 61
    评论
读者写者问题是指多个线程同时访问共享资源,其中有些线程是只读访问,有些线程是写访问,需要保证线程间的同步和互斥。在 C 语言中,可以使用线程库来实现读者写者问题。 以下是一个基于线程的读者写者问题解决方案: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #define MAX_READERS 5 #define MAX_WRITERS 5 pthread_mutex_t mutex; pthread_cond_t cond_read; pthread_cond_t cond_write; int read_count = 0; int write_count = 0; void *reader(void *arg) { int id = *(int*)arg; while (1) { pthread_mutex_lock(&mutex); while (write_count > 0) { pthread_cond_wait(&cond_read, &mutex); } read_count++; pthread_mutex_unlock(&mutex); printf("Reader %d is reading\n", id); sleep(1); pthread_mutex_lock(&mutex); read_count--; if (read_count == 0) { pthread_cond_signal(&cond_write); } pthread_mutex_unlock(&mutex); } return NULL; } void *writer(void *arg) { int id = *(int*)arg; while (1) { pthread_mutex_lock(&mutex); while (read_count > 0 || write_count > 0) { pthread_cond_wait(&cond_write, &mutex); } write_count++; pthread_mutex_unlock(&mutex); printf("Writer %d is writing\n", id); sleep(1); pthread_mutex_lock(&mutex); write_count--; pthread_cond_signal(&cond_write); pthread_cond_broadcast(&cond_read); pthread_mutex_unlock(&mutex); } return NULL; } int main() { pthread_t readers[MAX_READERS]; pthread_t writers[MAX_WRITERS]; int i; int *id; pthread_mutex_init(&mutex, NULL); pthread_cond_init(&cond_read, NULL); pthread_cond_init(&cond_write, NULL); for (i = 0; i < MAX_READERS; i++) { id = malloc(sizeof(int)); *id = i; pthread_create(&readers[i], NULL, reader, id); } for (i = 0; i < MAX_WRITERS; i++) { id = malloc(sizeof(int)); *id = i; pthread_create(&writers[i], NULL, writer, id); } for (i = 0; i < MAX_READERS; i++) { pthread_join(readers[i], NULL); } for (i = 0; i < MAX_WRITERS; i++) { pthread_join(writers[i], NULL); } pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond_read); pthread_cond_destroy(&cond_write); return 0; } ``` 在这个例子中,我们使用了一个互斥量 `mutex` 和两个条件变量 `cond_read` 和 `cond_write` 来实现读者写者问题的同步和互斥。`read_count` 和 `write_count` 变量用来记录正在读和正在写的线程数量。读者线程在执行前需要先检查是否有写者在写入,如果有则等待条件变量 `cond_read` 的信号。如果没有写者在写入,则增加 `read_count` 计数器,执行读操作,然后减少 `read_count`。如果 `read_count` 减少为 0,说明当前没有读者,可以发送 `cond_write` 条件变量的信号,唤醒等待的写者线程。写者线程在执行前需要先检查是否有读者在读或写者在写,如果有任意一个条件成立,则等待条件变量 `cond_write` 的信号。如果没有读者写者,则增加 `write_count` 计数器,执行写操作,然后减少 `write_count`。写者线程在完成写操作后发送 `cond_write` 的信号,唤醒等待的写者线程,同时发送 `cond_read` 的广播信号,唤醒所有等待的读者线程。 这是一个简单的读者写者问题解决方案,你可以根据自己的需求进行修改和优化。
评论 61
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值