读者/写者问题与进程同步——读者优先
读者/写者问题的描述如下:
有一个被许多进程共享的数据区,这个数据区可以是一个文件,或者主存的一块空间,甚至可以是一组处理器寄存器。有一些只读取这个数据区的进程(reader)和一些只往数据区中写数据的进程(writer)。以下假设共享数据区是文件。这些读者和写者对数据区的操作必须满足以下条件:读—读允许;读—写互斥;写—写互斥。这些条件具体来说就是:
(1)任意多的读进程可以同时读这个文件;
(2)一次只允许一个写进程往文件中写;
(3)如果一个写进程正在往文件中写,禁止任何读进程或写进程访问文件;
(4)写进程执行写操作前,应让已有的写者或读者全部退出。这说明当有读者在读文件时不允许写者写文件。
(5)读者优先,当有读者在读文件时,对随后到达的读者和写者,要首先满足读者,阻塞写者。这说明只要有一个读者活跃,那么随后而来的读者都将被允许访问文件,从而导致写者长时间等待,甚至有可能出现写者被饿死的情况。
#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <string.h>
#define MAX_THREAD 10 //待测试的线程数
typedef struct{ //表示测试数据格式
char thread_name[3]; //线程名
unsigned int require_moment; //请求操作时刻
unsigned int persist_time; //操作持续时间
}TEST_INFO;
TEST_INFO test_data[MAX_THREAD]={ //测试数据表
{"r1",0,15}, // r表示读者线程
{"r2",2,7}, //w表示写者线程
{"w1",3,10},
{"r3",4,8},
{"w2",5,4},
{"w3",6,5},
{"w4",8,2},
{"r4",14,2},
{"r5",38,2},
{"w5",39,2}
};
//r1,r2,r3,r4,w1,w2,w3,w4,r5,w5
int read_count=0; //记录正在读文件的读者数
CRITICAL_SECTION CS_DATA; //用于保护文件的临界区变量
HANDLE h_mutex_read_count=CreateMutex(NULL,FALSE,"mutex_read_count"); //读者计数器互斥体
//读者优先时的读者线程
void RF_reader_thread(void *data){
char thread_name[3]; //存放线程名称
strcpy(thread_name,((TEST_INFO *)data)->thread_name);
Sleep(((TEST_INFO *)data)->require_moment*1000);
WaitForSingleObject(h_mutex_read_count,-1); //申请进入关于读者计数器的临界区相当于P操作
read_count++;
if(read_count==1)
EnterCriticalSection(&CS_DATA); //申请进入关于文件的临界区相当于P操作
ReleaseMutex(h_mutex_read_count); //离开关于读者计数器的临界区相当于V操作
printf("%s ",thread_name);
Sleep(((TEST_INFO *)data)->persist_time*1000); //用延迟相应秒来模拟读文件操作
WaitForSingleObject(h_mutex_read_count,-1);
read_count--;
if(read_count==0)
LeaveCriticalSection(&CS_DATA); //离开关于文件的临界区相当于V操作
ReleaseMutex(h_mutex_read_count);
}
//读者优先时的写者线程
void RF_writer_thread(void *data){
Sleep(((TEST_INFO *)data)->require_moment*1000);
EnterCriticalSection(&CS_DATA);
printf("%s ",((TEST_INFO *)data)->thread_name);
Sleep(((TEST_INFO *)data)->persist_time*1000); //用延迟相应秒来模拟写文件操作
LeaveCriticalSection(&CS_DATA);
}
//读者优先时的初始化程序
void reader_first(){
int i=0;
HANDLE h_thread[MAX_THREAD];
printf("读优先申请次序:");
for(i=0;i<MAX_THREAD;i++){
printf("%s ",test_data[i].thread_name);
};
printf("\n");
printf("读优先操作次序:");
InitializeCriticalSection(&CS_DATA); //初始化临界区变量
for(i=0;i<MAX_THREAD;i++){ //根据线程名称创建不同的线程
if(test_data[i].thread_name[0]=='r') //名称的首字母是’r’则创建读者线程
h_thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RF_reader_thread),&test_data[i],0,NULL);
else //名称的首字母是’w’则创建写者线程
h_thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(RF_writer_thread),&test_data[i],0,NULL);
}
WaitForMultipleObjects(MAX_THREAD,h_thread,TRUE,-1); //等待所有线程结束
printf("\n");
}
//主程序
int main(){
char select;
while(1){
printf("|-----------------------------------|\n");
printf("| 1:reader first |\n");
printf("| 2:exit |\n");
printf("|-----------------------------------|\n");
printf("select a function(1~2):");
do{
select=(char)getch();
}while(select!='1'&&select!='2');
switch(select){
case '1':
reader_first();
break;
case '2':
system("pause");
return 0;
printf("\nPress any key to continue.");
getch();
}
}