一、实验目的
(1)回顾操作系统进程、线程的有关概念,针对经典的同步、互斥、死锁与饥饿问题进行并发程序设计。
(2)了解互斥体对象,利用互斥与同步操作编写读者-写者问题的并发程序,加深对P(即semWait)、V(即semSignal)原语以及利用P、V原语进行进程间同步与互斥操作的理解。
二、总体设计(含背景知识或基本原理与算法、或模块介绍、设计步骤等)
背景知识:
读者写者问题:有读者和写者两组并发进程,共享一个文件,当两个或两个以上的读进程同时访问共享数据时不会产生副作用,但若是某个写进程和其他进程同时访问共享数据时则可能会导致数据不一致的错误。要求:1.允许多个读者进程同时执行读操作。2.只允许一个写者往文件中写信息;3.任一写者在完成写操作之前不允许其他读者或写者工作;4.写者执行写操作前应让所有读者和写者全部退出。。
实验要求:
根据实验五中所熟悉的P、V原语对应的实际WindowsAPI函数,参考教材中读者-写者问题的算法原理,实现第一类读者-写者问题(读者优先)。
题目分析:两种进程,写进程对文件访问前后都需要互斥,所有设置一个互斥信号量;对于读进程则利用count计数器,当第一个读者访问时,就对文件加锁,当最后一个读者访问完就对文件解锁;而对count的判断和修改也需要一个互斥信号量;为了防止写者由于源源不断的读者而饿死,所有当有写者申请写时,需要控制count的值不能增加,所有又需要一个信号量。
设计步骤:(1)设置三个互斥信号量,和一个count计数器。
(2)写进程,一个P(w)判断是否有其他访问者,然后P(m)对文件加锁,开始写文件,完成释放V(w),V(m)。
(3)读进程,先用P(w)判断是否有写者进程再写或者申请写,然后一个P©实现对count的判断和修改,if判断如果count==0,就用P(m)对文件加锁,然后count自加,释放V©,V(w),开始读文件,完成先获得P©然后count自减,if判断count等于0,就解锁V(w),然后释放V©。
(4)Main函数通过创建读写进程,并实际程序结束出口。
完整代码:
#include <windows.h>
#include <iostream>
int WriterID=0;//记录写者ID
int ReaderID=0;//记录读者ID
int count=0;//记录同一时间访问的读者数目
bool p_ccontinue = true; //控制程序结束
HANDLE WSemaphore;//实现写者优先的信号量
HANDLE Mutex; //用于线程间的互斥
HANDLE Count_Mutex; //用于保证对count变量的互斥访问
HANDLE Writer_Mutex; //用于实现写者优先
DWORD WINAPI Writer(LPVOID lpPara)
{
while(p_ccontinue){//程序在运行中
WaitForSingleObject(Writer_Mutex,INFINITE); //p(mutex);
WaitForSingleObject(Mutex,INFINITE); //p(mutex);
printf("%d开始写文件",WriterID);
Sleep(1000);
printf("...%d完成写文件\n",WriterID);
WriterID++;
ReleaseMutex(Mutex); //V(mutex);
ReleaseMutex(Writer_Mutex); //V(mutex);
}return 0;
}
DWORD WINAPI Reader(LPVOID lpPara){
while(p_ccontinue){
WaitForSingleObject(Writer_Mutex,INFINITE); //P(mutex1);
WaitForSingleObject(Count_Mutex,INFINITE); //P(mutex1);
if(count==0) WaitForSingleObject(Mutex,INFINITE); //p(mutex);
count++;
ReleaseMutex(Count_Mutex); //V(mutex);
ReleaseMutex(Writer_Mutex); //V(mutex);
Sleep(1000);
WaitForSingleObject(Count_Mutex,INFINITE); //P(mutex1);
printf("已有%d个读者完成读文件\n",ReaderID++);
count--;
if(count==0) ReleaseMutex(Mutex); //V(mutex);
ReleaseMutex(Count_Mutex); //V(mutex);
}return 0;
}
int main()
{
Mutex = CreateMutex(NULL,FALSE,NULL);
Count_Mutex = CreateMutex(NULL,FALSE,NULL);
Writer_Mutex= CreateMutex(NULL,FALSE,NULL);
int WRITER_COUNT = 5,READER_COUNT = 10;
int THREADS_COUNT = WRITER_COUNT+READER_COUNT;
HANDLE hThreads[THREADS_COUNT]; //各线程的 handle
DWORD writerID[WRITER_COUNT]; //写者线程的标识符
DWORD readerID[READER_COUNT]; //读者线程的标识符
for (int i=0;i<WRITER_COUNT;++i){
hThreads[i]=CreateThread(NULL,0,Writer,NULL,0,&writerID[i]);
if (hThreads[i]==NULL) return -1;}
for (i=0;i<READER_COUNT;++i){
hThreads[WRITER_COUNT+i]=CreateThread(NULL,0,Reader,NULL,0,&readerID[i]);
if (hThreads[i]==NULL) return -1;}
while(p_ccontinue){
if(getchar()) p_ccontinue = false;//按回车后终止程序运行}
return 0;
}