读者/写者问题与进程同步——读者优先

读者/写者问题与进程同步——读者优先

读者/写者问题的描述如下:
有一个被许多进程共享的数据区,这个数据区可以是一个文件,或者主存的一块空间,甚至可以是一组处理器寄存器。有一些只读取这个数据区的进程(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();
    }
}

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值