zoukankan      html  css  js  c++  java
  • OS第6次实验报告:使用信号量解决进程互斥访问

    • 姓名:巫艳珍
    • 学号:201821121034
    • 班级:计算1812

    1.读者-写者问题

    (1)读者-写者问题描述如下情况:对象在多个线程之间共享,一些线程只读数据,一些线程只写数据。为保证写入和读取的正确性,操作限制:

    • 写-写互斥,即不能有两个写者同时进行写操作。  
    • 读-写互斥,即不能同时有一个线程在读,而另一个线程在写。 
    • 读-读允许,即可以有一个或多个读者在读。

    (2)解决方案:读者优先或写者优先。

    2.伪代码

    (1)读者优先

    当已经有线程在读数据的时候,其他读线程无需等待,而写线程需要等待所有正在进行的读操作之后才能执行。

    semaphore rw=1;//实现对文件的互斥访问,表示当前是否有进程访问共享文件
    int readcount=0;//记录访问文件的读进程数
    semaphore mutex=1;//保证互斥访问
    //写者
    writer(){
      while(1){
         P(rw);//写文件前进行加锁
         写文件
         V(rw);//写文件之后进行解锁        
    }  
    } 
    //读者
    reader(){
        while(1){
            P(mutex);//读进程互斥访问readcount
            if(readcount==0)
                P(rw);//第一个读进程“加锁”,阻塞写者
            readcount++;//访问文件的读进程数加1
            V(mutex);
            读文件
            P(mutex);
            readcount--;
            if(readcount==0)
                 V(rw);//解锁
            V(mutex);
    }
    }    

    问题:只有所有读者都读完,写者才能写,当读者过多时,会导致写者出现“饿死”的情况

    (2)写者优先

    写者优先需要满足的要求:多个读者可以进行读;写者要互斥,只允许一个写者写,不能读者写者同时进行;写者优先于读者,一旦有写者,后续的读者必须等待,唤醒时优先考虑写者,直到最后的写者完成操作。

    尽量满足写操作,不能并发,但可以排队,优先于等待的读线程获得执行权

    int readcount=0,writecount=0;
    5个信号量,mutex1,mutex2,mutex3,r,w
    writer(){//写进程
        P(mutex2);
        writecount++;
        if(writecount==1)
            P(r);//第一个为写者,阻止后面的读者
        V(mutex2);
        P(w);
        写文件
        V(w);
        P(mutex2);
        writecount--;
       if(writecount==0) V(r);
       V(mutex2);
    }
    reader(){//读者进程
        P(mutex3);
        P(r);
        P(mutex1);
        readcount++;
    
     if(readcount==1)//第一个读者,互斥写者
            P(w);
        V(mutex1);
        V(r)
        V(mutex3);
        读文件
        P(mutex1);
        readcount--;
        if(readcount==0) V(w);//读者为最后一个,唤醒写者
        V(mutex1);
    }

    3.完整代码

    #include<string.h>
    #include<unistd.h>
    #include<pthread.h>
    #include<stdlib.h>
    #include<sys/ipc.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<sys/shm.h>
    #include<semaphore.h>
    #include<stdio.h>
    
    int readcount=0,writecount=0; 
    pthread_t p1,p2;
    sem_t mutex1,mutex2,mutex3,r,w;//5个信号量 
    
    
    
    void* writer(void* arg)
    {
        int i = *(int*)arg;
        printf("进程%d想要写入
    ",i);
        sem_wait(&mutex2);
        writecount++;
        if(writecount==1) //若第一个为写者,阻止后续的读者 
            sem_wait(&r);
        sem_post(&mutex2);
        sem_wait(&w);//写者互斥 
        printf("进程%d正在写入
    ",i);
        sleep(4);
        printf("进程%d完成写入
    ",i);    
        sem_post(&w);
        sem_wait(&mutex2);
        writecount--;
        if(writecount==0) sem_post(&r);//所有的写者写完才能让P(r)的读者readcount增加 
        sem_post(&mutex2);
    }
    
    void* reader(void* arg){
        int i = *(int*)arg;
        printf("进程%d想要读取
    ",i);
        sem_wait(&mutex3);
        sem_wait(&r);
        sem_wait(&mutex1);
        readcount++;
        if(readcount==1)//若第一个为读者,互斥写者 
            sem_wait(&w);
        sem_post(&mutex1);
        sem_post(&r);
        sem_post(&mutex3);
        printf("进程%d正在读取
    ",i);
        sleep(2);
        printf("进程%d完成读取
    ",i);    
        sem_wait(&mutex1); 
        readcount--;
        if(readcount==0)//读者运行完释放写者,读写互斥 
            sem_post(&w);
        sem_post(&mutex1);
        
    }
    
    int main(int argc,char *argv[]){
        int ret;
        int pro_num=atoi(argv[1]);//输入进程数 
        sem_init(&r,0,1);//初始化信号量 
        sem_init(&w,0,1);
        sem_init(&mutex1,0,1);
        sem_init(&mutex2,0,1);
        sem_init(&mutex3,0,1);
        readcount=0;
        writecount=0;
        if(argc!=2){
            fprintf(stderr,"wrong
    ");
            return 1;
        }
        printf("共有%d个进程
    ",pro_num);
        int n[pro_num+1];
        for(int i=0;i<pro_num;i++){
            int s=rand()%2+1;
            int f=rand()%2;
            sleep(s);
            n[i]=i;
            if(f){
                ret=pthread_create(&p1,NULL,reader,&n[i]);
                if(ret!=0){
                    printf("error to create reader!
    ");
                    exit(1);
                }
            }
            else{
                ret=pthread_create(&p2,NULL,writer,&n[i]);
                if(ret!=0){
                    printf("error to create writer!
    ");
                    exit(1);
                }
            }
        }
        pthread_join(p2,NULL);
        pthread_join(p1,NULL);
        sleep(20);
        return 0;
        
    }
    • 信号量常用函数:

        sem_init:初始化信号量sem_t,初始化的时候可以指定信号量的初始值,以及是否可以在多进程间共享。

        sem_wait:一直阻塞等待直到信号量>0。

        sem_post:使信号量加1。

    • pthread_join()函数:以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果线程已经结束,那么该函数会立即返回。

    4.结果截图及解释

    (1)结果截图:

     

    (2)解释:实现的是写者优先

    一共十个进程,进程2等待进程1完成写入后进行读取,进程3想要读取,能够实现与进程2同时读取,进程4想要读取,进程2和3读取完毕进程4开始写入,此时进程5、6、7想要读取,只有等进程4完成写操作才能读取,当进程9和进程10均想要写入时,不能同时进行写操作,待进程9完成写操作时进程10才写入。

    5.遇到的问题

     在编译的时候出现报错collect2:error:Id returned 1 exit status

    解决:编译时连接库,在编译命令后添加:-lpthread -ldl -lm

     

     

  • 相关阅读:
    HDU2732 Leapin' Lizards 网络流 最大流 SAP
    POJ1459 Power Network 网络流 最大流
    HDU3718 Similarity KM
    HDU3488 Tour KM
    HDU2853 Assignment KM
    HDU1507 Uncle Tom's Inherited Land* 二分图匹配 匈牙利算法 黑白染色
    POJ1469 COURSES 二分图匹配 匈牙利算法
    HDU4185 Oil Skimming 二分图匹配 匈牙利算法
    POJ3041 Asteroids 二分图匹配 匈牙利算法
    BZOJ2553 [BeiJing2011]禁忌 AC自动机 矩阵
  • 原文地址:https://www.cnblogs.com/will-h/p/12983846.html
Copyright © 2011-2022 走看看