精华内容
下载资源
问答
  • 实验5 利用信号量实现进程互斥 【实验目的】 (1) 理解互斥概念、信号量机制及信号量结构; (2) 掌握信号量的使用方法; (3) 掌握PV操作的定义; (4) 掌握PV操作实现互斥的方法。 【实验原理/实验基础知识】...

    实验5 利用信号量实现进程互斥
    【实验目的】
    (1) 理解互斥概念、信号量机制及信号量结构;
    (2) 掌握信号量的使用方法;
    (3) 掌握PV操作的定义;
    (4) 掌握PV操作实现互斥的方法。
    【实验原理/实验基础知识】
    一、 互斥
    多进程不能同时访问共享的临界资源的现象称为互斥。
    二、 Linux信号量结构
    每一个信号量集由一个sem_array结构来描述,该结构定义在文件/usr/src/linux-2.4/include/linux/sem.h中(若实验使用操作系统为ubuntu,则在以下路径中查找/usr/src/linux-header2.6.32-21/include/linux/sem.h)。
    三、 有关信号量的系统调用函数

    1. 创建一个新的信号量集或获取一个已经存在的信号量集
      命令格式:int semget(key_t key, int nsems, int semflg)
      返回值:正确时返回信号量集的标识符号,错误时返回-1。
      参数说明:
    1. key:信号量集的key值。
      a) 使用IPC_PRIVATE,由系统产生key值并返回标识符,或者返回key值已存在的信号量集的标识符。
      b) 若key值不使用IPC_PRIVATE,而是由用户指定一个非0的整型数值,则对信号量集的打开或存取操作依赖于semflag参数的取值。
    2. nsems:指定打开或者新创建的信号量集将包括的信号量的数目。如果该key值的信号量集已存在,而semflg只指定IPC_CREAT标志,那么参数nsems必须与原来的值一致,否则也会返回错误信息。该参数最大值在linux/sem.h中定义如下。
      #define SEMMSL 250 /* <= 8000 */
    3. semflg:当key值不为IPC_PRIVATE时使用。
      a) 若只设置semflag的IPC_CREAT位,则创建一个信号量集,如果该信号量集已经存在,则返回其标识符号。
      b) 若设置semflag的IPC_CREAT|IPC_EXCL位,则创建一个新的信号量集,如果该key值的信号量集已经存在,则返回错误信息。
      c) 只设置IPC_EXCL位而不设置IPC_CREAT位没有任何意义。
    1. 对信号量的P、V操作
      命令格式:int semop(int semid, struct sembuf * sops, unsigned nsops);
      返回值:正确时返回0,错误时返回-1。
      参数说明:
      (1) semid:信号量集的标识符号,由semget()得到。
      (2) sops:指向一个sembuf结构数组,该数组的每个元素对应一次信号量操作。其sembuf数据结构如下。
      struct sembuf
      {
      unsigned short sem_num;
      short sem_op;
      short sem_flg;
      }
      其参数含义如下:
      sem_num:标明是信号量集的第几个元素,第一个信号量为0,第二个信号量为1,依次类推。
      sem_op:确定对信号量采取何种操作,可以为负数、正数、零。
    1. sem_op为负数则相当于P操作,从信号量的值中减去sem_op的绝对值:
       差值大于0:表示该进程可以使用临界资源进入临界区;
       差值小于0:在没有指定IPC_NOWAIT的情况下,该进程睡眠,并插入sem_queues等待队列尾部,直到请求的条件得到满足;如果指定了IPC_NOWAIT,则出错返回。
    2. sem_op为正数,此时相当于V操作,把它的值加到信号量中,意味着该进程释放资源。如果是互斥则出临界区,释放临界资源。
    3. sem_op为0,则该进程进入睡眠,直到信号量的值也为0。
      系统会按顺序检查信号量等待队列(sem_pending)中的每一个成员,查看在当前信号量的状态下,其请求的操作是否可以成功,如果可以,则将它从等待队列中唤醒,并插入就绪队列等待调度运行。
      sem_flg:指明操作的执行模式,它有两个标志位。一个是IPC_NOWAIT,指明以非阻塞方式操作信号量。另一个是SEM_UNDO,指明内核为信号量操作保留恢复值。
      (3) nsops:是第二个参数所指向的sembuf结构数组中元素的个数,如果只有一个信号量,则为1。
      实验中使用该系统调用实现P、V操作,使用格式为:
      struct sembuf P,V;
      semop(semid,&P,1);
      semop(semid,&V,1);
    1. 信号量集的控制函数
      命令格式:int semctl(int semid, int semnum, int cmd, union semun arg);
      返回值:正确时根据cmd的不同返回需要的值或0,错误时返回-1。
      参数说明:
      (1) semid:信号量集的标识符,由semget()得到。
      (2) semnum:指定semid信号量集的第几个信号量,在撤销信号量集时,此时参数可以默认。
      (3) cmd用于指定操作类别。其取值如下:
       GETVAL:返回semnum指定的信号量的semval域值。
       SETVAL:置信号量semval域值为arg.val。
       GETPID:返回semnum指定的信号量的sempid,即最近对该信号量进行操作的进程ID。
       GETNCNT:返回semncnt。
       GETZNCT:返回semzcnt。
       GETALL:返回所有信号量的值。
       SETALL:通过对arg.arrary更新所有信号量的值。
       IPC_STAT:获取信号量集的sem_array,存入arg.buf。
       IPC_SET:将arg.buf数据结构的sem_perm.uid、sem_perm.gid、sem_perm.mode成员赋给信号量的sem_array结构。
       IPC_RMID:删除指定信号量集。
       IPC_INFO:获取信号量集相关的信息,存放在arg.buf中。
      (4) arg为5种数据的共用体类型semun,该类型在include/linux/sem.h中定义如下:
      union semun
      {
      int val;
      struct semid_ds *buf;
      unsigned short *array;
      struct seminfo *_buf;
      void *_pad;
      };
    1. 该数据表示int数值时,用于GETVAL、SETVAL或GETPID等设置或获取整型数据的操作。
    2. 该数据指向semid_ds(即sem_array)结构数据时,用于IPC_STAT或IPC_SET等针对信号量集进行的操作。
    3. 该数据指向unsigned short数组时,用于GETALL或SETALL。
    4. 该数据指向seminfo结构时,用于IPC_INFO操作,所指向的seminfo结构在include/linux/sem.h中定义,其定义如下:
      struct seminfo
      {
      int semmap;
      int semmni;
      int semmns;
      int semmnu;
      int semmsl;
      int semopm;
      int semume;
      int semusz;
      int semvmx;
      int semaem;
      };
      上述系统调用使用系列头文件:
      #include<sys/types.h>
      #inclue<linux/sem.h>
      四、 信号量及其P、V操作的实现方式
    1. 定义信号量标识符号
      int semid;
    2. 定义信号量数据结构
    1. 定义P、V操作所用的数据结构
      struct sembuf P,V;
    2. 定义给信号量赋初值的参数数据结构
      union semun arg;
    1. 申请只有一个信号量的信号量集
      semid=semget(IPC_PRIVATE,1,IPC_0666);
      IPC_PRIVATE:可由系统产生key值;
      1:表示信号量集中只有一个信号量;
      IPC_0666:表示操作权限。0666表示任意用户可读可写,只设置semflag的IPC_CREAT位,则创建一个信号量集。
    2. 分别对每个信号量semid赋初值
      arg.val=初值;
      semctl(semid,0,SETVAL,arg);
      其中0表示第0个信号量,arg的值由arg.val决定,所以必须事先为arg.val赋值。
    3. 定义信号量P操作
      P.sem_num=0;
      P.sem_op=-1;
      P.sem_flg=SEM_UNDO;
    4. 定义信号量V操作
      V.sem_num=0;
      V.sem_op=1;
      V.sem_flg=SEM_UNDO;
    5. 对信号量semid执行P操作
      semop(mutexid,&P,1);
    6. 对信号量semid执行V操作
      semop(mutexid,&V,1);
    7. 撤销信号量
      semctl(semid,IPC_REID,0);
      信号量非普通变量,对它的赋值操作只能通过semctl(semid,0,SETVAL,arg)进行,其值的修改只能通过P、V操作,而不能使用普通的赋值语句。因此其初值和信号量的P、V操作需要事先定义好后才能在进程中执行。
      【实验环境】VMware Workstation、RedHat
      【实验步骤】
      一、父子进程以非互斥方式共享访问临界资源
    1. 创建父子进程
    2. 父子进程共享一个临界资源,每个进程循环进入该临界区3次。
    3. 父进程每次进入临界区后显示“parent in”,出临界区显示“parent out”。
      printf(“parent in\n”);
      sleep(1);
      printf(“parent out\n”);
    4. 子进程每次进入临界区后显示“child in”,出临界区显示“child out”。
      printf(“child in\n”);
      sleep(1);
      printf(“child out\n”);
    5. 观察执行结果。
      #include<stdio.h>标准输入输出函数库
      #include<stdlib.h>是C语言库头文件之一,包含了以下函数:
      1 字符串转换为数字的函数,包括atoi, atof, strtol等。
      2 随机数函数,包括srand, rand等。
      3 内存分配释放函数,如malloc,calloc,realloc,free等。
      4 程序运行控制函数,如exit, abort等。
      5 系统访问相关函数,如printenv, setenv,system等。
      6 常用算法函数,如qsort, bsearch, abs,div等。
      #include<unistd.h>不是c语言的东西,是linux/unix的系统调用,包含了许多U N I X系统服务的函数原型,例如 read,write和getpid函数。unistd.h在unix中类shu似于window中的windows.h!
      #include<sys/types.h>此头文件还包含适当时应使用的多个基本派生类型。尤其是以下类型更为重要:clock_t 表示系统时间(以时钟周期为单位)。  dev_t 用于设备号。  off_t 用于文件大小和偏移量。  ptrdiff_t 是一种带符号整型,用于对两个指针执行减法运算后所得的结果。  size_t 反映内存中对象的大小(以字节为单位)。  ssize_t 供返回字节计数或错误提示的函数使用。  time_t 以秒为单位计时。  所有这些类型在 ILP32 编译环境中保持为 32 位值,并会在 LP64 编译环境中增长为 64 位值。
      #include<sys/sem.h>是glibc提供的调用接口,#include <linux/sem.h>是系统提供的调用接口,本身不是同一个实现。

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<linux/sem.h>
    int mutexid;
    int main()
    {
    int chld,i,j;
    while((chld=fork())-1);
    if(chld>0)
    {
    i=1;
    while(i<=3)
    {
    sleep(1);
    printf(“parent in.\n”);
    sleep(1);
    printf(“parent out.\n”);
    i++;
    }
    wait(0);
    exit(0);
    }
    else
    {
    j=1;
    while(j<=3)
    {
    sleep(1);
    printf(“child in.\n”);
    sleep(1);
    printf(“child out.\n”);
    j++;
    }
    exit(0);
    }
    }
    在这里插入图片描述
    在这里插入图片描述
    二、PV操作实现进程互斥。以实验步骤一为基础,增加PV操作,实现父子进程互斥访问临界区。
    (1) 定义与PV操作相关的数据结构;
    (2) 定义信号量,给信号量赋值;
    (3) 定义PV操作;
    (4) PV操作实现进程互斥。
    (5) 观察执行结果,并与实验步骤一的结果比较。
    #include<unistd.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<linux/sem.h>
    int mutexid;
    int main()
    {
    int chld,i,j;
    struct sembuf P,V;
    union semun arg;
    untexid = semget(IPC_PRIVATE,1,0666|IPC_CREAT);
    arg.val=1;
    if(semctl(mutexid,0,SETVAL,arg)
    -1)
    perror(“semctl setval error.”);
    P.sem_num=0;
    P.sem_op=-1;
    P.sem_flg=SEM_UNDO;
    V.sem_num=0;
    V.sem_op=1;
    V.sem_flg=SEM_UNDO;
    while((chld=fork())==-1)
    if(chld>0)
    {
    i=1;
    while(i<=3)
    {
    sleep(1);
    semop(mutexid,&P,1);//进入临界区,执行P操作
    printf(“parent in.\n”);
    sleep(1);
    printf(“parent out.\n”);//出临界区,执行V操作
    semop(mutexid,&V,1);
    i++;
    }
    wait(0);
    semctl(mutexid,IPC_RMID,0);
    exit(0);
    }
    else
    {
    j=1;
    while(j<=3)
    {
    sleep(1);
    semop(mutexid,&P,1);
    printf(“child in.\n”);
    sleep(1);
    printf(“child out.\n”);
    semop(mutexid,&V,1);
    j++;
    }
    exit(0);
    }
    }
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    【实验报告】
    填写《信息技术学院学生上机实验报告》。
    【思考题】
    (1) 实验步骤一的结果说明什么?
    (2) P、V操作在各进程代码中的位置应该如何处理?

    展开全文
  • 利用信号量实现进程互斥 利用信号量实现前驱关系 分析进程同步和互斥问题的方法步骤 信号量机构是一种功能较强的机制,可用来解决互斥与同步的问题,它只能被两个标准的原语wait(S)和signal(S)来访问,也可以记为...


    信号量机构是一种功能较强的机制,可用来解决互斥与同步的问题,它只能被两个标准的原语wait(S)和signal(S)来访问,也可以记为“P操作”和“V操作”。

    原语是指完成某种功能且不被分割不被中断执行的操作序列,通常可由硬件来实现完成不被分割执行特性的功能。如前述的“Test-and-Set”和“Swap”指令,就是由硬件实现的原子操作。原语功能的不被中断执行特性在单处理机时可由软件通过屏蔽中断方法实现。

    原语之所以不能被中断执行,是因为原语对变量的操作过程如果被打断,可能会去运行另一个对同一变量的操作过程,从而出现临界段问题。如果能够找到一种解决临界段问题的元方法,就可以实现对共享变量操作的原子性。

    整型信号量

    整型信号量被定义为一个用于表示资源数目的整型量S,wait和signal操作可描述为:

        wait(S){
            while (S<=0);
            S=S-1;
        }
        signal(S){
            S=S+1;
        }
    

    wait操作中,只要信号量S<=0,就会不断地测试。因此,该机制并未遵循“让权等待” 的准则,而是使进程处于“忙等”的状态。

    记录型信号量

    记录型信号量是不存在“忙等”现象的进程同步机制。除了需要一个用于代表资源数目的整型变量value外,再增加一个进程链表L,用于链接所有等待该资源的进程,记录型信号量是由于釆用了记录型的数据结构得名。记录型信号量可描述为:

    typedef struct{
        int value;
        struct process *L;
    } semaphore;
    

    相应的wait(S)和signal(S)的操作如下:

    void wait (semaphore S) { //相当于申请资源
        S.value--;
        if(S.value<0) {
            add this process to S.L;
            block(S.L);
        }
    }
    

    wait操作,S.value–,表示进程请求一个该类资源,当S.value<0时,表示该类资源已分配完毕,因此进程应调用block原语,进行自我阻塞,放弃处理机,并插入到该类资源的等待队列S.L中,可见该机制遵循了“让权等待”的准则。

    void signal (semaphore S) {  //相当于释放资源
        S.value++;
        if(S.value<=0){
            remove a process P from S.L;
            wakeup(P);
        }
    }
    

    signal操作,表示进程释放一个资源,使系统中可供分配的该类资源数增1,故S.value++。若加1后仍是S.value<=0,则表示在S.L中仍有等待该资源的进程被阻塞,故还应调用wakeup 原语,将S.L中的第一个等待进程唤醒。

    利用信号量实现同步

    信号量机构能用于解决进程间各种同步问题。设S为实现进程P1、P2同步的公共信号量,初值为0。进程P2中的语句y要使用进程P1中语句x的运行结果,所以只有当语句x执行完成之后语句y才可以执行。其实现进程同步的算法如下:

    semaphore S = 0;  //初始化信号量
    P1 ( ) {
        // …
        x;  //语句x
        V(S);  //告诉进程P2,语句乂已经完成
    }
    P2()){
        // …
        P(S) ;  //检查语句x是否运行完成
        y;  // 检查无误,运行y语句
        // …
    }
    

    利用信号量实现进程互斥

    信号量机构也能很方便地解决进程互斥问题。设S为实现进程Pl、P2互斥的信号量,由于每次只允许一个进程进入临界区,所以S的初值应为1(即可用资源数为1)。只需把临界区置于P(S)和V(S)之间,即可实现两进程对临界资源的互斥访问。其算法如下:

    semaphore S = 1;  //初化信号量
    P1 ( ) {
        // …
        P(S);  // 准备开始访问临界资源,加锁
        // 进程P1的临界区
        V(S);  // 访问结束,解锁
        // …
    }
    P2() {
        // …
        P(S); //准备开始访问临界资源,加锁
        // 进程P2的临界区;
        V(S);  // 访问结束,解锁
        // …
    }
    

    互斥的实现是不同进程对同一信号量进行P、V操作,一个进程在成功地对信号量执行了 P操作后进入临界区,并在退出临界区后,由该进程本身对该信号量执行V操作,表示当前没有进程进入临界区,可以让其他进程进入。

    利用信号量实现前驱关系

    信号量也可以用来描述程序之间或者语句之间的前驱关系。图2-8给出了一个前驱图,其中S1, S2, S3, …, S6是最简单的程序段(只有一条语句)。为使各程序段能正确执行,应设置若干个初始值为“0”的信号量。例如,为保证S1 -> S2、 S1 -> S3的前驱关系,应分别设置信号量a1、a2。同样,为了保证 S2 -> S4、S2 ->S5、S3 -> S6、S4 -> S6、S5 -> S6,应设置信号量bl、b2、c、d、e。

    image

    图2-8 前驱图举例

    实现算法如下:

    semaphore  al=a2=bl=b2=c=d=e=0;  //初始化信号量
    S1() {
        // …
        V(al);  V(a2) ;  //S1已经运行完成
    }
    S2() {
        P(a1);  //检查S1是否运行完成
        // …
        V(bl); V(b2); // S2已经运行完成
    }
    S3() {
        P(a2);  //检查S1是否已经运行完成
        // …
        V(c);  //S3已经运行完成
    }
    S4() {
        P(b1);  //检查S2是否已经运行完成
        // …
        V(d);  //S4已经运行完成
    }
    S5() {
        P(b2);  //检查S2是否已经运行完成
        // …
        V(e);  // S5已经运行完成
    }
    S6() {
        P(c);  //检查S3是否已经运行完成
        P(d);  //检查S4是否已经运行完成
        P(e);  //检查S5是否已经运行完成
        // …;
    }
    

    分析进程同步和互斥问题的方法步骤

    1. 关系分析。找出问题中的进程数,并且分析它们之间的同步和互斥关系。同步、互斥、前驱关系直接按照上面例子中的经典范式改写。

    2. 整理思路。找出解决问题的关键点,并且根据做过的题目找出解决的思路。根据进程的操作流程确定P操作、V操作的大致顺序。

    3. 设置信号量。根据上面两步,设置需要的信号量,确定初值,完善整理。

    展开全文
  • 信号量机制实现进程互斥 信号量机制实现进程同步

    信号量机制实现进程互斥

    在这里插入图片描述

    信号量机制实现进程同步

    在这里插入图片描述
    在这里插入图片描述

    信号量机制实现前驱关系

    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 目录思维导图实现进程互斥实现进程同步实现前驱关系 思维导图 实现进程互斥 实现进程同步 实现前驱关系

    思维导图

    在这里插入图片描述
    在这里插入图片描述

    实现进程互斥

    在这里插入图片描述

    实现进程同步

    在这里插入图片描述
    在这里插入图片描述

    实现前驱关系

    在这里插入图片描述

    展开全文
  • 信号量 实现进程互斥与同步

    千次阅读 2018-03-24 10:25:43
    信号量基本术语 现代计算机系统中,多个...信号量(semaphore)是1965年由荷兰人Dijkstra提出的一种卓有成效的进程间同步及互斥工具。信号量在操作系统中实现时一般作为一个整数变量,这种信号量称为整型信号量。...
  • 信号量实现进程互斥.c

    千次阅读 2017-01-05 23:03:47
    /*用信号量实现进程互斥” * 进程共享一套代码(fork之前的代码),fork之后相互独立 * sudo kill -9 $(pidof ./a.out) //杀死所有a.out进程 */#include #include #include #include #include #include #define...
  • 一、我们在前面讲进程间通信的时候提到过进程互斥的概念,下面写个程序来模拟一下,程序流程如下图: 即父进程打印字符O,子进程打印字符X,每次打印一个字符后要sleep 一下,这里要演示的效果是,在打印程序...
  • 进程打印输出一个o的字样,子进程打印输出x的字样,父进程打印输出o之后睡眠,睡眠一个随机的时间,然后再次输出o,子进程也是同样的动作,只是输出的是x。 父子进程执行流程如下: 父进程进程 ...
  • 一、我们在前面讲进程间通信的时候提到过进程互斥的概念,下面写个程序来模拟一下,程序流程如下图: 即父进程打印字符O,子进程打印字符X,每次打印一个字符后要sleep 一下,这里要演示的效果是,在打印程序的...
  • 信号量机制实现进程互斥

    千次阅读 2019-07-13 16:50:16
    2.信号量机制实现进程互斥 3.信号量机制实现进程同步 4.信号量机制实现前驱关系 5.小结 1.总览 2.信号量机制实现进程互斥 3.信号量机制实现进程同步 4.信号量机制实现前驱关系 5.小结 ...
  • 信号量机制实现进程互斥2. 信号量机制实现进程同步3. 信号量机制实现前驱关系知识回顾与重要考点 知识总览 1. 信号量机制实现进程互斥 2. 信号量机制实现进程同步 3. 信号量机制实现前驱关系 知识回顾与重要...
  • 2.3.5用信号量机制实现进程互斥、同步、前驱关系 知识总览 1.实现进程互斥 2.实现进程同步 3.实现前驱关系 4.总结
  • 文章目录1 信号量机制1.1 整形信号量1.2 记录形信号量1.3 信号量机制小结2 用信号量机制实现进程互斥、同 步、前驱关系2.1 信号量机制实现进程互斥2.2 信号量机制实现进程同步2.3 信号量机制实现前驱关系2.4 信号量...
  • 信号量机制实现互斥互斥信号量mutex的初值:1 mutex = 1 表示一次只允许一个进程访问 PV操作实现互斥:PV操作成对出现,把操作夹在里面 倘若没有P操作:无法实现互斥 倘若没有V操作:一直占用着程序得不到释...
  • 2.3.5 用信号量机制实现进程互斥、同步、前驱关系 目录 2.3.5 用信号量机制实现进程互斥、同步、前驱关系 2.3.5.1用信号量机制实现进程互斥 2.3.5.2用信号量机制实现进程同步 2.3.5.3信号量机制实现前驱关系 ...
  • 信号量实现进程互斥、同步和前驱关系
  • 2.3.5 信号量机制实现进程互斥、同步、前驱关系 知识来源: B站王道考研 实现进程互斥 分析并发进程的关键活动,划定临界区(如:对临界资源打印机的访问就应放在临界区) 设置互斥信号量mutex,初始值为1 在临界区...
  • 不用信号量进程互斥

    千次阅读 2013-05-13 22:53:50
    不用信号量进制来实现进程互斥,你想过吗?让我们来感受下这段优美的代码吧! 这段代码好像在两个进程互斥上性能比较好,进程多了就不行了。 非本人原创!
  • 二、信号量机制实现进程互斥 注意: 1.信号量mutex表示进入临界区的名额 2.对不同的临界资源需要设置不同的互斥信号量 3.P、V操作必须成对出现,缺少P(mutex)就不能保证临界资源的互斥访问。缺少V会导致资源永不...
  • 一,进程互斥 1,分析问题,设置临界区 2,设置互斥信号量S.value(临界资源),初值为1 3,进入临界区之前对信号量执行P操作(S.value--),互斥信号量值为0,表示资源被占用,切换到其它进程时,就不能继续执行...
  • 原视频链接 进程同步: 实际是用来表述不同进程之间存在制约关系。 进程互斥进程互斥的软件实现方法: 进程互斥硬件实现方法: 中断屏蔽方法: TestAndSet指令 TS指令: ...信号量机制 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,687
精华内容 674
关键字:

信号量实现进程互斥