• 进程间通信IPC-信号量


    semget 

    semget函数创建一个新的信号量或是获得一个已存在的信号量键值。

    1 int semget(key_t key, int num_sems, int sem_flags);

    第一个参数key是一个用来允许不相关的进程访问相同信号量的整数值。所有的信号量是为不同的程序通过提供一个key来间接访问的,对于每一个信号量系统 生成一个信号量标识符。信号量键值只可以由semget获得,所有其他的信号量函数所用的信号量标识符都是由semget所返回的。还有一个特殊的信号量key值,IPC_PRIVATE(通常为0),其作用是创建一个只有创建进程可以访问的信号量。这通常并没有有用的目的,而幸运的是,因为在某些Linux系统上,手册页将IPC_PRIVATE并没有阻止其他的进程访问信号量作为一个bug列出。num_sems参数是所需要的信号量数目。这个值通常总是1。sem_flags参数是一个标记集合,与open函数的标记十分类似。低九位是信号的权限,其作用与文件权限类似。另外,这些标记可以与 IPC_CREAT进行或操作来创建新的信号量。设置IPC_CREAT标记并且指定一个已经存在的信号量键值并不是一个错误。如果不需 要,IPC_CREAT标记只是被简单的忽略。我们可以使用IPC_CREAT与IPC_EXCL的组合来保证我们可以获得一个新的,唯一的信号量。如果这个信号量已经存在,则会返回一个错误。如果成功,semget函数会返回一个正数;这是用于其他信号量函数的标识符。如果失败,则会返回-1。

    semop 

    函数semop用来改变信号量的值: 

    第一个参数,sem_id,是由semget函数所返回的信号量标识符。第二个参数,sem_ops,是一个指向结构数组的指针,其中的每一个结构至少包含下列成员:

    1 struct sembuf {
    2     short sem_num;
    3     short sem_op;
    4     short sem_flg;
    5 }
    第一个成员,sem_num,是信号量数目,通常为0,除非我们正在使用一个信号量数组。sem_op成员是信号量的变化量值。(我们可以以任何量改变信 号量值,而不只是1)通常情况下中使用两个值,-1是我们的P操作,用来等待一个信号量变得可用,而+1是我们的V操作,用来通知一个信号量可用。最后一个成员,sem_flg,通常设置为SEM_UNDO。这会使得操作系统跟踪当前进程对信号量所做的改变,而且如果进程终止而没有释放这个信号量, 如果信号量为这个进程所占有,这个标记可以使得操作系统自动释放这个信号量。将sem_flg设置为SEM_UNDO是一个好习惯,除非我们需要不同的行 为。如果我们确实变我们需要一个不同的值而不是SEM_UNDO,一致性是十分重要的,否则我们就会变得十分迷惑,当我们的进程退出时,内核是否会尝试清 理我们的信号量。semop的所用动作会同时作用,从而避免多个信号量的使用所引起的竞争条件。我们可以在手册页中了解关于semop处理更为详细的信息。

    semctl 。semctl函数允许信号量信息的直接控制:

    1 int semctl(int sem_id, int sem_num, int command, ...);

      

    第一个参数,sem_id,是由semget所获得的信号量标识符。sem_num参数是信号量数目。当我们使用信号量数组时会用到这个参数。通常,如果 这是第一个且是唯一的一个信号量,这个值为0。command参数是要执行的动作,而如果提供了额外的参数,则是union semun,根据X/OPEN规范,这个参数至少包括下列参数:

    1 union semun {
    2     int val;
    3     struct semid_ds *buf;
    4     unsigned short *array;
    5     struct seminfo* __buf;
    6 }

    许多版本的Linux在头文件(通常为sem.h)中定义了semun联合,尽管X/Open确认说我们必须定义我们自己的联合。如果我们发现我们确实需 要定义我们自己的联合,我们可以查看semctl手册页了解定义。如果有这样的情况,建议使用手册页中提供的定义,尽管这个定义与上面的有区别。有多个不同的command值可以用于semctl。在这里我们描述两个会经常用到的值。要了解semctl功能的详细信息,我们应该查看手册页。这两个通常的command值为:SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。IPC_RMID:当信号量不再需要时用于删除一个信号量标识。semctl函数依据command参数会返回不同的值。对于SETVAL与IPC_RMID,如果成功则会返回0,否则会返回-1。

    使用信号量 

     1 #include <sys/sem.h>
     2 #include <stdio.h>
     3 #include <stdlib.h>
     4 #include <unistd.h>
     5 #include <sys/wait.h>
     6 
     7 union semun
     8 {
     9      int val;
    10      struct semid_ds* buf;
    11      unsigned short int* array;
    12      struct seminfo* __buf;
    13 };
    14 
    15 void pv( int sem_id, int op )
    16 {
    17     struct sembuf sem_b;
    18     sem_b.sem_num = 0;
    19     sem_b.sem_op = op;
    20     sem_b.sem_flg = SEM_UNDO;
    21     semop( sem_id, &sem_b, 1 );
    22 }
    23 
    24 int main( int argc, char* argv[] )
    25 {
    26     int sem_id = semget( IPC_PRIVATE, 1, 0666 );
    27 
    28     union semun sem_un;
    29     sem_un.val = 1;
    30     semctl( sem_id, 0, SETVAL, sem_un );
    31 
    32     pid_t id = fork();
    33     if( id < 0 )
    34     {
    35         return 1;
    36     }
    37     else if( id == 0 )
    38     {
    39         printf( "child try to get binary sem
    " );
    40         pv( sem_id, -1 );
    41         printf( "child get the sem and would release it after 5 seconds
    " );
    42         sleep( 5 );
    43         pv( sem_id, 1 );
    44         exit( 0 );
    45     }
    46     else
    47     {
    48         printf( "parent try to get binary sem
    " );
    49         pv( sem_id, -1 );
    50         printf( "parent get the sem and would release it after 5 seconds
    " );
    51         sleep( 5 );
    52         pv( sem_id, 1 );
    53     }
    54 
    55     waitpid( id, NULL, 0 );
    56     semctl( sem_id, 0, IPC_RMID, sem_un );
    57     return 0;
    58 }
  • 相关阅读:
    Reference Counting GC (Part two :Partial Mark & Sweep)
    Reference Counting GC (Part one)
    Union File System
    Linux Cgroups
    Mark Sweep GC
    取模运算
    负数取模怎么算
    牛客【2021寒假集训营第一场】J-一群小青蛙呱蹦呱蹦呱
    记codeforces一个简单模拟题
    筛法求素数
  • 原文地址:https://www.cnblogs.com/borey/p/5625977.html
Copyright © 2020-2023  润新知