精华内容
下载资源
问答
  • 文章目录Linux POSIX 信号量 命名信号量与未命名信号量命名信号量的创建初始化一个未命名信号量发布信号量和等待信号量获取信号量的当前值关闭一个命名信号量删除一个命名信号量销毁一个未命名信号量 注意: 1、...

    Linux POSIX 信号量 命名信号量与未命名信号量


    注意:
    1、Linux信号量是一个递加递减的正整数,而不是ON、OFF的bool量。
    2、Linux信号量数值为0时,尝试去递减该信号量,则会阻塞进程或者线程,直到某处让该信号量递加一次,才能触发被阻塞的递减操作。
    POSIX信号量分为两种:
    命名信号量:这种信号量有一个名字,不相关的进程可以通过名字访问同一个信号量,通过sem_open()函数调用;
    未命名信号量:这种信号量没有名字,它位于内存中预定的位置(全局变量、静态变量等),未命名信号量主要在线程间共享。也可以在进程间共享,但是该信号量必须处于共享内存区域

    信号量的基本使用流程如下:

    //创建命名(未命名)信号量 ---> 递增信号值 ---> 递减信号值  ---> 获取当前信号值  ---> 删除信号量与进程间的关联关系  ---> 删除该信号量
    sem_open()/sem_init() ---> sem_post() ---> sem_wait() ---> sem_getvalue() ---> sem_close()                ---> sem_unlink()
    

    命名信号量的创建

    #include <fcntl.h>
    #include <sys/stat.h>
    #include <semaphore.h>
    
    /*
     *  @Description: 创建一个新的命名信号量 或 打开一个既有信号量
     *  @Para       : const char * name         信号量的名称
     *                int oflag                 位掩码  等于0则为打开一个既有信号量  为O_CREAT则创建一个信号量
     *                mode_t mode               (创建信号量时)位掩码 可以设置信号量的文件权限,如S_IRUSR S_IWUSR S_IXUSR等
     *                unsigned int value        (创建信号量时)指定信号量的初始信号值。
     *  @return     : 成功返回创建或者打开的信号量指针,失败返回SEM_FAILED
    **/
    sem_t * sem_open(const char * name, int oflag /* , mode_t mode, unsigned int value */);
    
    //例:
    if(sem_open("/mysem", O_CREAT | O_EXCL, 0644, 0) == SEM_FAILED)
        printf("sem creat failed!\r\n");
    

    注意:

    1. 信号量的名称参数name,必须以斜线开头,后面跟着一个或多个非斜线字符的名字,如 “/mysem”, 名称的最长字符数为 NAME_MAX(255) - 4;
    2. 当int oflag = O_CREAT | O_EXCL 时,如果信号量不存在则创建,如果存在,则函数调用失败返回;
    3. 如果sem_open()用于打开一个既有信号量,则仅适用前两个参数即可。如果是创建新信号量,则可以通过mode_t mode设置新创建的信号量的文件权限(Owner Group Other, Read Write Execute等),通过 unsigned int val可以设置信号量的初值。
    4. 在sem_open()返回的sem_t * 指针指向的变量的副本进行操作,结果是未知的,应禁止该行为。
        //错误代码,禁止该类操作
        sem_t * sp;
        sem_t sem2;
        sp = sem_open(...);
        sem2 = *sp;
        sem_wait(&sem2);
    
    1. 当打开或者创建命名信号量时,会自动建立进程与命名信号量间的关联关系;

    初始化一个未命名信号量

    #include <semaphore.h>
    
    /*
     *  @Description: 初始化一个未命名信号量
     *  @Para       : sem_t *sem            待初始化的信号量指针
     *                int pshared           线程共享、进程共享区分,等于0则为线程间共享,不为0则为进程间共享
     *                unsigned int value    指定信号量的初始信号值。
     *  @return     : 成功返回0,失败返回-1
    **/
    int sem_init(sem_t *sem, int pshared, unsigned int value);
    
    //例:
    sem_t mysem;    //创建信号量
    if(sem_init(&mysem, 0, 0) == -1)    //初始化信号量
        printf("sem_init failed!\r\n");
    

    注意:

    1. int pshared 等于0则为线程间共享,不为0则为进程间共享,如果是进程间共享,则该信号量必须是共享内存区域;
    2. 对一个已经初始化的未命名信号量进行初始化操作将会导致未定义的行为,要确保所有的进程、线程中只进行过一次sem_init()信号量初始化操作;
    3. 对信号量的副本进行操作,结果是未定义的。也就是说,总是只能在最初的信号量上执行操作。

    发布信号量和等待信号量

    #include <semaphore.h>
    
    /*
     *  @Description: 发布一个信号量,及信号量数值加一
     *  @Para       : sem_t *sem            要发布的信号量
     *  @return     : 成功返回0,失败返回-1
    **/
    int sem_post(sem_t *sem);
    
    /*
     *  @Description: 等待一个信号量,及信号量数值减一,如果等待的信号量值为0,
     *                则阻塞进程,直到某处使用sem_post()
     *  @Para       : sem_t *sem            等待的信号量
     *  @return     : 成功返回0,失败返回-1
    **/
    int sem_wait(sem_t *sem);
    
    /*
     *  @Description: 尝试等待一个信号量,如果等待的信号量值为0,不阻塞进程,立即失败返回。
     *  @Para       : sem_t *sem            等待的信号量
     *  @return     : 成功返回0,失败返回-1
    **/
    int sem_trywait(sem_t *sem);
    
    /*
     *  @Description: 等待一个信号量,如果等待的信号量值为0,则阻塞进程。
     *                直到某处使用sem_post(),或者到达abs_timeout指定的绝对时间。
     *  @Para       : sem_t *sem            等待的信号量
     *                const struct timespec * abs_timeout   超时的绝对时间
     *  @return     : 成功返回0,失败返回-1
    **/
    int sem_timedwait(sem_t *sem, const struct timespec * abs_timeout);
    

    注意:

    1. 如果同一时刻有多个进程、线程在使用sem_wait()阻塞的等待一个信号,当使用sem_post()发布一个信号时,默认的SCHED_OTHER调度机制下,哪个进程先被唤醒时不确定的。如果使用的是SCHED_RR或SCHED_FIFO调度机制,则最先被唤醒的进程是优先级最高、等待时间最长的进程;
    2. sem_timedwait()的abs_timeout时间参数是一个绝对时间参数,如果需要设置一个相对时间,如5s后结束等待,使用clock_gettime()获取CLOCK_REALTIME当前绝对时间值,并在此基础上加上5s,赋值到abs_timeout;

    获取信号量的当前值

    信号量的值是一个正整数,当没有sem_wait()等待信号时,使用sem_post()多次发布信号,则会使信号量当前值一直累加,等有sem_wait()时,则递减一。信号量值可以记录信号发送的次数,不遗漏已发送的信号。

    #include <semaphore.h>
    
    /*
     *  @Description: 获取信号量的当前值。
     *  @Para       : sem_t *sem   等待的信号量
     *                int * sval   信号量当前值
     *  @return     : 成功返回0,失败返回-1
    **/
    int sem_getvalue(sem_t * sem, int * sval);
    

    注意:

    1. 当信号量的值为正数时,则正常返回信号量的值,但当信号量的值为零,且此时有多个sem_wait()在等待该信号量时,sval的具体返回值依赖于系统实现,Linux系统直接返回0,而其它一些系统可能返回绝对值等于sem_wait()中阻塞等待数目的负数。
    2. 使用sem_getvalue()获得信号量数目具有较短的时效性,因为可能刚获取信号量数目,就被其它线程打断,在其它线程中发送了信号量,当再次返回原线程时,已经取出的信号量值并不是真实值;

    关闭一个命名信号量

    该函数仅用于命名信号量,当进程打开一个命名信号量时,系统会记录命名信号量与进程间的关联关系,使用sem_close()可以断开其关联关系。

    #include <semaphore.h>
    
    /*
     *  @Description: 关闭命名信号量与进程的关联关系
     *  @Para       : sem_t *sem   等待的信号量
     *                int * sval   信号量当前值
     *  @return     : 成功返回0,失败返回-1
    **/
    int sem_close(sem_t * sem);
    

    删除一个命名信号量

    该函数仅用于命名信号量,把该信号量标记为当所有的进程与命名信号量的关联关系都被关闭时,可以销毁该信号量。如果信号量没有与进程的关联关系,则立刻删除。反之则等待所有关联关系关闭再删除。

    #include <semaphore.h>
    
    /*
     *  @Description: 删除一个命名信号量
     *  @Para       : const char * name   命名信号量命称
     *  @return     : 成功返回0,失败返回-1
    **/
    int sem_unlink(const char * name);
    

    销毁一个未命名信号量

    该函数仅用于未命名信号量,只有在不存在线程、进程使用sem_wait()等待该信号量时,才能安全的销毁该信号量。

    #include <semaphore.h>
    
    /*
     *  @Description: 摧毁一个未命名信号量
     *  @Para       : sem_t * sem   未命名信号量
     *  @return     : 成功返回0,失败返回-1
    **/
    int sem_destroy(sem_t * sem);
    

    注意:

    1. 其参数sem_t * sem 必须是是一个未命名信号量,并且已经被sem_init()初始化过。
    2. 在一些实现上,省略sem_destroy()调用不会导致问题的发生,但在其它实现上,不调用sem_destroy()会导致资源泄露,为保持可移植性,应调用sem_destroy()。
    展开全文
  • Linux信号量

    2021-03-21 12:43:11
    手工删除信号量 一.信号量的概念   信号量(信号灯)本质上是一个计数器,用于协调多个进程(但不包括父子进程)对共享数据对象的读/写。它不以传输数据为目的,主要是用来保护共享资源(共享

    一.信号量的概念

      信号量(信号灯)本质上是一个计数器,用于协调多个进程(但不包括父子进程)对共享数据对象的读/写。它不以传输数据为目的,主要是用来保护共享资源(共享内存、消息队列、socket连接池、数据库连接池等),保证共享资源在一个时刻只有一个进程独享。
    在这里插入图片描述
      就像公共厕所一样,它是共享资源,它有一个信号灯,提示人们它现在的状态,有没有人在使用。这样就保证了测试一次只能让一个人使用。这也说明了信号灯本质上是一个计数器,厕所里面有人,就显示有人,没人就显示为无人。

      信号量是一个特殊的变量,只允许进程对它进行等待信号和发送信号操作
    在这里插入图片描述
    在这里插入图片描述

    最简单的信号量是取值0和1的二元信号量,这是信号量最常见的形式。

      通用信号量(可以取多个正整数值)和信号量集方面的知识比较复杂,应用场景也比较少。本文只介绍二元信号量。

    二.相关的函数

    1.包含的头文件

      Linux中提供了一组函数用于操作信号量,程序中需要包含以下头文件:

    #include <sys/types.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
    

    2.semget 函数

    在这里插入图片描述
      semaphore——信号量
      get——获得

    2.1.函数的声明及参数

      semget函数用来获取或创建信号量,它的原型如下:

    int semget(key_t key, int nsems, int semflg);
    

      1)参数key是信号量的键值,typedef unsigned int key_t,是信号量在系统中的编号,不同信号量的编号不能相同,这一点由程序员保证。key用十六进制表示比较好。
      这个key值是针对系统而言的,政府安装了一批公共厕所门,在政府里的文件的编号为 0x5005。

      2)参数nsems是创建信号量集中信号量的个数,该参数只在创建信号量集时有效,这里固定填1。
      为公共厕所装门,一共装了多少扇门。

      3)参数sem_flags是一组标志,如果希望信号量不存在时创建一个新的信号量,可以和值IPC_CREAT做按位或操作。如果没有设置IPC_CREAT标志并且信号量不存在,就会返错误(errno的值为2,No such file or directory)。

      4)如果semget函数成功,返回信号量集的标识;失败返回-1,错误原因存于error中。
      公共厕所的门安装好了,其实就是厕所设置好了,要告诉百姓厕所门在哪,说是不可能 0x5005 吧,这样谁会知道?所以给它起个名字,叫做牛逼路9527号公共厕所门。这个也是它的标识。
    在这里插入图片描述

    2.2. 示例

      1)获取键值为0x5000的信号量,如果该信号量不存在,就创建它,代码如下:

    int semid=semget(0x5000,1,0640|IPC_CREAT);
    

      2)获取键值为0x5000的信号量,如果该信号量不存在,返回-1,errno的值被设置为2,代码如下:

    int semid= semget(0x5000,1,0640)

    3.semctl 函数

    3.1 函数的声明及参数

    在这里插入图片描述

      该函数用来控制信号量(常用于设置信号量的初始值和销毁信号量),它的原型如下:

    int semctl(int semid, int sem_num, int command, ...);
    

      1)参数semid是由semget函数返回的信号量标识。
      这个是控制函数,首先我要知道去控制谁吧,所以第一个参数是semget函数返回的信号量标识。

      2)参数sem_num是信号量集数组上的下标,表示某一个信号量,填0。
      就好比公共厕所,多个坑位(多个共享资源),那么就需要多个信号量(门)。每个信号量有在信号集合里面有序号,从0开始。

      3)参数cmd是对信号量操作的命令种类,
    在这里插入图片描述

    常用的有以下两个:

      IPC_RMID:销毁信号量,不需要第四个参数;

      SETVAL:初始化信号量的值(信号量成功创建后,需要设置初始值),这个值由第四个参数决定。第四参数是一个自定义的共同体,如下:

    // 用于信号灯操作的共同体。
      union semun
      {
        int val;
        struct semid_ds *buf;
        unsigned short *arry;
      };
    

      这个就好比说,厕所建好了,一开始设置为没有人使用的状态。。

    3.2 示例

      1)销毁信号量。

     semctl(semid,0,IPC_RMID);
    

      2)初始化信号量的值为1,信号量可用。

    
    union semun sem_union;
      sem_union.val = 1;
      semctl(semid,0,SETVAL,sem_union);
    

      semid——是哪里的信号量要设置初始值(哪里的门),

      0——序号为0的信号量要设置初始值

      sem_union.val = 1;——初始值为1

    4.semop函数

    在这里插入图片描述

    4.1 函数的声明及参数

      (1)该函数有两个功能:
    1)等待信号量的值变为1,如果等待成功,立即把信号量的值置为0,这个过程也称之为等待锁;
      这就像,平时生活中排队上厕所的例子。那些坑位就是共享资源,其实上面的出租车例子可以改成公共厕所。我们会发现,当有人在里面上厕所,关了门之后,那个门的把手附近就会变成红色。这就相当信号量的值为0,我们想要上厕所就要等里面的人出来(信号量的值为1)。然后我们再进去把门给锁上,门把手附近会变成红色(把信号量的值置为0)

    2)把信号量的值置为1,这个过程也称之为释放锁。
      就相当于我上完了厕所,出来了让别人使用。
    在这里插入图片描述

      (2)函数声明:

    int semop(int semid, struct sembuf *sops, unsigned nsops);
    

      1)参数semid是由semget函数返回的信号量标识。

      2)参数nsops是操作信号量的个数,即sops结构变量的个数,设置它的为1(只对一个信号量的操作)。

      3)参数sops是一个结构体,如下:

    struct sembuf
    {
      short sem_num;   // 信号量集的个数,单个信号量设置为0。
      short sem_op;    // 信号量在本次操作中需要改变的数据:-1-等待操作;1-发送操作。
      short sem_flg;   // 把此标志设置为SEM_UNDO,操作系统将跟踪这个信号量。
                       // 如果当前进程退出时没有释放信号量,操作系统将释放信号量,避免资源被死锁。
    };
    

    4.2 示例

      1)等待信号量的值变为1,如果等待成功,立即把信号量的值置为0;

    struct sembuf sem_b;
      sem_b.sem_num = 0;
      sem_b.sem_op = -1;
      sem_b.sem_flg = SEM_UNDO;
      semop(sem_id, &sem_b, 1);
    

      2)把信号量的值置为1。

    struct sembuf sem_b;
      sem_b.sem_num = 0;
      sem_b.sem_op = 1;
      sem_b.sem_flg = SEM_UNDO;
      semop(sem_id, &sem_b, 1);
    

    三.示例程序

    1. 示例程序(book259.cpp)

      为了便于理解,我把信号量的操作封装成CSEM类,称之为信号灯,类似互斥锁,包括初始化信号灯、等待信号灯、挂出信号灯和销毁信号灯。

    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/ipc.h>
    #include <sys/sem.h>
     
    class CSEM
    {
    private:
      union semun  // 用于信号灯操作的共同体。
      {
        int val;
        struct semid_ds *buf;
        unsigned short *arry;
      };
     
      int  sem_id;  // 信号灯描述符。
    public:
      bool init(key_t key); // 如果信号灯已存在,获取信号灯;如果信号灯不存在,则创建信号灯并初始化。
      bool wait();          // 等待信号灯挂出。
      bool post();          // 挂出信号灯。
      bool destroy();       // 销毁信号灯。
    };
     
    int main(int argc, char *argv[])
    {
       CSEM sem;
     
       // 初始信号灯。
       if (sem.init(0x5000)==false) { printf("sem.init failed.\n"); return -1; }
       printf("sem.init ok\n");
      
       // 等待信信号挂出,等待成功后,将持有锁。
       if (sem.wait()==false) { printf("sem.wait failed.\n"); return -1; }
       printf("sem.wait ok\n");
     
       sleep(50);  // 在sleep的过程中,运行其它的book259程序将等待锁。
      
       // 挂出信号灯,释放锁。
       if (sem.post()==false) { printf("sem.post failed.\n"); return -1; }
       printf("sem.post ok\n");
      
       // 销毁信号灯。
       // if (sem.destroy()==false) { printf("sem.destroy failed.\n"); return -1; }
       // printf("sem.destroy ok\n");
    }
     
    bool CSEM::init(key_t key)
    {
      // 获取信号灯。
      if ( (sem_id=semget(key,1,0640)) == -1)
      {
        // 如果信号灯不存在,创建它。
        if (errno==2)
        {
          if ( (sem_id=semget(key,1,0640|IPC_CREAT)) == -1) { perror("init 1 semget()"); return false; }
     
          // 信号灯创建成功后,还需要把它初始化成可用的状态。
          union semun sem_union;
          sem_union.val = 1;
          if (semctl(sem_id,0,SETVAL,sem_union) <  0) { perror("init semctl()"); return false; }
        }
        else
        { perror("init 2 semget()"); return false; }
      }
     
      return true;
    }
     
    bool CSEM::destroy()
    {
      if (semctl(sem_id,0,IPC_RMID) == -1) { perror("destroy semctl()"); return false; }
     
      return true;
    }
     
    bool CSEM::wait()
    {
      struct sembuf sem_b;
      sem_b.sem_num = 0;
      sem_b.sem_op = -1;
      sem_b.sem_flg = SEM_UNDO;
      if (semop(sem_id, &sem_b, 1) == -1) { perror("wait semop()"); return false; }
       
      return true;
    }
     
    bool CSEM::post()
    {
      struct sembuf sem_b;
      sem_b.sem_num = 0;
      sem_b.sem_op = 1;  
      sem_b.sem_flg = SEM_UNDO;
      if (semop(sem_id, &sem_b, 1) == -1) { perror("post semop()"); return false; }
     
      return true;
    }
    

    2.代码解析

    2.1 初始化信号灯函数:bool init(key_t key)

      1.先尝试获取信号灯——
    semget(key,1,0640)

      2.如果信号灯不存在,就创建信号灯——sem_id=semget(key,1,0640|IPC_CREAT)

      3.信号灯创建成功后,将信号灯初始化成可用的状态——semctl(sem_id,0,SETVAL,sem_union)

    2.2 等待信号灯挂出函数 bool wait();

    3.测试

      第一步:运行book259程序,它会创建键值为5000的信号灯,并持有锁,如下:
    在这里插入图片描述
      这就相当于我进去上厕所,把门给锁上了。

      第二步:立即再运行一个book259程序,它会获取键值为5000的信号灯,并等待锁,如下:
    在这里插入图片描述
      我还在厕所里面,来的人在外面等待

      第三步,当第一次运行的book259程序sleep完50秒之后,释放锁,第二个运行book259的程序将获得锁;

    在这里插入图片描述
      我出厕所了

    在这里插入图片描述
      在外面等的人进去了。

      第四步,可以启动更多的book259程序,它们将排队等待锁。

    四.其他的操作命令

    1.查看系统的信号量

      用 ipcs -s 可以查看系统的信号量,内容有键值(key),信号量编号(semid),创建者(owner),权限(perms),信号量数(nsems)。
    在这里插入图片描述

    2.手工删除信号量

      用ipcrm sem 信号量编号,可以手工删除信号量,如下:
    在这里插入图片描述

    展开全文
  • linux ipc信号量

    2018-09-13 22:56:00
    ipcs 命令,可以看到当前系统上的共享资源实例 ...linux 操作信号量的函数有三个:semget, semop, semctl semget 声明为: #include <sys/types.h> #include <sys/ipc.h> #include &l...

    ipcs 命令,可以看到当前系统上的共享资源实例

    ipcrm 命令,可以删除一个共享资源实例

    linux 操作信号量的函数有三个:semget, semop, semctl

    semget 声明为:

           #include <sys/types.h>
           #include <sys/ipc.h>
           #include <sys/sem.h>
    
           int semget(key_t key, int nsems, int semflg);

    key 是一个键值,用来标识一个全局唯一的信号量集。要通过信号量通信的进程需要使用相同的键值来获取该信号量。

    nsems 表示要创建/获取的信号量集中信号量的数目。如果是创建信号量,这个值必须指定。如果是获取已经存在的信号量,可以把它设置成0.

    semflg 指定一组标志。它的低端9个比特是该信号量的权限。相当于文件操作权限,类似open函数的mode参数。而且,它还可以和IPC_CREAT标志按位“或”运算来创建新的信号量集。

    成功返回一个正整数,它是信号量集的标识符;失败返回-1,并设置errno

    semop 系统调用改变信号量的值,即执行P、V操作:

    int semop(int semid, struct sembuf *sops, size_t nsops);

    semid 是由 semget 返回的信号量集标识符,用来指定被操作的目标信号量集。

    sops 是 struct sembug 结构体,定义为:

    /* Structure used for argument to `semop' to describe operations.  */
    struct sembuf
    {
      unsigned short int sem_num;   /* semaphore number */
      short int sem_op;     /* semaphore operation */
      short int sem_flg;        /* operation flag */
    };

    sem_num 是信号量集的编号,0表示第一个信号量。

    sem_op 指定操作类型,可选值为正整数、0、负整数。

    sem_flg 可选值是 IPC_NOWAIT, SEM_UNDO。IPC_NOWAIT指,无论信号量集操作是否成功,semop调用都立刻返回。SEM_UNDO含义是,当进程退出时,取消正在进行的semop操作

    nsops参数指定要执行的操作个数,即sops数组中元素的个数。semop对数组sops中的每个元素按照数组顺序依次执行操作,并且这个过程是原子操作。

    semop成功返回0,失败返回-1并设置errno。失败的时候,sops数组中指定的所有操作都不执行。

    semctl用来对信号量进行直接操作:

    int semctl(int semid, int semnum, int cmd, ...);

    semid 是semget调用返回的信号量集标识符。semnum指定被操作的信号量在信号量集中的编号。cmd指定要执行的命令。有的命令需要传入第4个参数,这个参数类型由用户定义,但是,内核给出了它的格式,而且,必须是这个格式:

               union semun {
                   int              val;    /* Value for SETVAL */
                   struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
                   unsigned short  *array;  /* Array for GETALL, SETALL */
                   struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                               (Linux-specific) */
               };

    cmd 的值比较多,不列举了,可以看manpage,其中,

    IPC_STAT 将信号量集关联的内核数据结构复制到semun.buf中,

    GETVAL 获取信号量的semval的值

    SETVAL 将信号量的semval值设置为semun.val

    IPC_RMID 立即移除信号量集,唤醒所有等待信号量集的进程

    该函数返回值根据cmd不同而不同。失败返回-1,并设置errno

     

    semget函数第一个参数key可以设置为 IPC_PRIVATE(值为0),这样,无论信号量是否存在,都会创建一个新的信号量

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <sys/sem.h>
    
    
    //这个联合体需要手动定义
    union semun
    {
        int              val;    /* Value for SETVAL */
        struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
        unsigned short  *array;  /* Array for GETALL, SETALL */
        struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                   (Linux-specific) */
    };
    
    void ErrExit(const char* reason)
    {
        fprintf(stderr, "%s: %d, %s\n", reason, errno, strerror(errno));
        exit(1);
    }
    
    int initsem(int key = 0)
    {
        int semid = -1;
        if (-1 == (semid = semget(key, 1, 0666 | IPC_CREAT)))
        {
            ErrExit("semget");
        }
    
        // 信号量初始值为1
        union semun sem_un;
        sem_un.val = 1;
        if (-1 == semctl(semid, 0, SETVAL, sem_un))
        {
            ErrExit("semctl");
        }
    
        return semid;
    }
    
    void destroysem(int semid)
    {
        if (-1 == semctl(semid, 0, IPC_RMID))
        {
            ErrExit("semctl del");
        }
    }
    
    // -1 为 p 操作
    void P(int semid)
    {
        struct sembuf op;
        op.sem_num = 0;
        op.sem_op = -1;
        op.sem_flg = SEM_UNDO;
        if (-1 == semop(semid, &op, 1))
        {
            ErrExit("semop p");
        }
    }
    
    // 1 为 v 操作
    void V(int semid)
    {
        struct sembuf op;
        op.sem_num = 0;
        op.sem_op = 1;
        op.sem_flg = SEM_UNDO;
        if (-1 == semop(semid, &op, 1))
        {
            ErrExit("semop v");
        }
    }
    
    int main(int argc, char const *argv[])
    {
        int semid = initsem();
        pid_t pid = fork();
    
        if (pid > 0)
        {
            P(semid);
            printf("in parent process...\n");
            sleep(1);
            V(semid);
    
            waitpid(pid, NULL, 0);
            // 删除信号量集
            destroysem(semid);
        }
        else if (0 == pid)
        {
            P(semid);
            printf("in child process...\n");
            sleep(1);
            V(semid);
        }
        else
        {
            ErrExit("fork");
        }
    
        return 0;
    }

     

    转载于:https://www.cnblogs.com/zuofaqi/p/9643787.html

    展开全文
  • Linux c 信号量

    2013-08-29 15:58:00
    信号量(通过进程通信实现进程间的同步) 信号量(semaphore)信号灯 信号量是共享内存整数数组.... 信号量就是根据数组中的值,决定阻塞还是解除阻塞 编程模型: ...4. 删除信号量 semctl 案例: A...

    信号量(通过进程通信实现进程间的同步)

    信号量(semaphore)信号灯

    信号量是共享内存整数数组.根据需要定义指定的数组长度

    信号量就是根据数组中的值,决定阻塞还是解除阻塞

    编程模型:

    1. 创建或者得到信号量 semget

    2. 初始化信号量中指定下标的值 semctl

    3. 根据信号量阻塞或者解除阻塞 semop

    4. 删除信号量 semctl

    案例:

    A: B:

    创建信号量 得到信号量

    初始化信号量 解除阻塞

    根据信号量阻塞

    删除信号量

    int semget(key_t key,

    int nums,//信号量数组个数

    int flags);//信号量的创建标记

    //创建IPC_CREAT|IPC_EXCL|0666

    //打开0

    返回: -1:失败

    >=0:成功返回信号量的ID

    int semctl(int semid,

    intnums,//对IPC_RMID无意义

    intcmd,//SETVAL(信号量值)IPC_RMID

    ...);//对IPC_RMID无意义

    参数:
    semid:信号集的标识符,即是信号表的索引。
    semnum:信号集的索引,用来存取信号集内的某个信号。
    cmd:需要执行的命令,有效值有 需要使用联合体semun赋值

    union semun{

    int val;

    struct semid_ds *buf;

    unsigned short *array;

    struct seminfo *_buf;

    };//需要自己定义该联合体,根据需要定义,需要那个字段就可以只定义那个

    int semop(

    int semid,//信号量ID

    struct sembuf*op,//对信号量的操作.操作可以是数组多个

    size_tnums,//第二个参数的个数

    );

    返回:

    -1:时失败

    0:成功

    struct sembuf

    {

    int sem_num;//下标

    int sem_op;

    int sem_flg;//建议为0.

    }


    sem_op:
    前提条件信号量是unsigned short int;
    不能<0.
    -:够减,则semop马上返回,不够减,则阻塞.
    +:执行+操作
    0:判定信号量>0,则阻塞,直到为0
    控制进程的搭配方式:
    +(解除阻塞) -(阻塞)
    0(阻塞) -(解除阻塞)

    代码:

    semA:

    #include<stdio.h>

    #include<unistd.h>

    #include<sys/ipc.h>

    #include<sys/sem.h>

    #include<stdlib.h>

    #include<signal.h>

    int semid;

    void deal(ints)

    {

    //4.删除信号量

    printf(“删除信号量…”);

    semctl(semid,0,IPC_RMID , 0);

    printf(“信号量已删除”);

    exit( -1 );

    }

    union semun{

    int val;

    struct semid_ds *buf;

    unsigned short *array;

    struct seminfo *_buf;

    };

    void main()

    {

    key_tkey;

    union semun v;//2.2定义初始化值

    int r;

    //3.1定义一个操作结构体

    structsembuf op[1]; //定义了两个操作

    signal(SIGINT , deal);

    //1.创建信号量

    key=ftok(“.” , 99);

    if(key == -1) printf(“ftok err :%m\n”) ,exit(-1);

    semid=semget(kay,1 /*信号量数组个数*/ , IPC_CREAT | IPC_EXCL | 0666);

    if( semget == -1) printf(“get err %m\n”) ,exit(-1);

    //2.初始化信号量

    //2.1定义一个联合体

    v.val=2;

    r=semctl(semid , 0 , SETVAL , v); //设置信号量的值

    if(r== -1) printf(“初始化失败:%m\n”) , exit(-1);

    //3.对信号量阻塞操作

    op[0].sem_num=0; //信号量的下标

    op[0].sem_op= 1; //信号量操作单位与类型

    op[0].sem_flg=0; //操作标记 IPC_NOWAIT(信号量值够不够减都返回 不阻塞)

    //SEM_UNDO 建议为0;

    while(1)

    {

    r=semop(semid , op ,1);

    printf(“信号量阻塞-1”);

    }

    }

    //semop操作减一 ,信号量值大于0,semop执行返回,信号量值等于0时,semop操作阻塞等待,直到信号量值大于0,在进行该操作

    semB:

    #include<stdio.h>

    #include<unistd.h>

    #include<sys/ipc.h>

    #include<sys/sem.h>

    #include<stdlib.h>

    union semun{

    int val;

    struct semid_ds *buf;

    unsigned short *array;

    struct seminfo *_buf;

    };

    void main()

    {

    intsemid;

    key_tkey;

    int r;

    //3.1定义一个操作结构体

    structsembuf op[1]; //定义了两个操作

    signal(SIGINT , deal);

    //1.得到信号量

    key=ftok(“.” , 99);

    if(key == -1) printf(“ftok err :%m\n”) ,exit(-1);

    semid=semget(kay,1 /*信号量数组个数*/ ,0);

    if( semget == -1) printf(“get err %m\n”) ,exit(-1);

    //3.对信号量阻塞操作

    op[0].sem_num=0; //信号量的下标

    op[0].sem_op= +1; //信号量操作单位与类型

    op[0].sem_flg=0; //操作标记 IPC_NOWAIT(信号量值够不够减都返回 不阻塞)

    //SEM_UNDO 建议为0;

    while(1)

    {

    r=semop(semid , op ,1);

    sleep(1);

    }

    }

    //进程semA进行信号量阻塞-1 semB进行信号量接触阻塞+1 , semB进程控制semA进程的执行

    展开全文
  • ipcs 命令可以查看当前进程的消息队列、共享内存、信号量信息: ipcrm -q MessageID //删除消息队列 ...ipcrm -s SemaphoreID //删除信号量 转载于:https://www.cnblogs.com/Mered1th/p/10744776.h...
  • Linux IPC 3 之 信号量

    2017-10-29 16:24:17
    2 内核信号量中的等待队列删除没有联系 3 内核信号量的相关函数 1 初始化 2 申请内核信号量所保护的资源 3 释放内核信号量所保护的资源 4 内核信号量的使用例程 四 用户态信号量 POSIX 信号量与SYSTEM V信号量的比较...
  • shmctl删除内存。信号量,虽说可以于通讯,但是更加适合于进程间的同步。...2、semctl:初始化信号量,控制信号量3、semop:做PV操作(对信号量做加减操作)ftok,共享内存,消息队列,信号量它们三个都是找一
  • 最全面的linux信号量解析

    万次阅读 多人点赞 2012-08-04 17:27:21
    2012-06-28 15:08 285人阅读 评论(0) 收藏 编辑 删除 ...信号量 ...一.什么是信号量 ...信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程) ...在学习信号量之前,我们必须先知道
  • Linux系统编程】POSIX有名信号量

    千次阅读 2019-11-08 11:11:01
    相关函数2.1 创建有名信号量2.2 关闭有名信号量2.3 删除有名信号量2.4 信号量P操作2.5 信号量V操作03. 程序示例04. 附录 01. 概述 在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量。无名信号量...
  • POSIX信号量接口,意在解决XSI信号量接口的几个不足之处: POSIX信号量接口相比于XSI信号量接口,允许更高性能的...XSI信号量删除后,使用该信号量标识符的操作将会出错返回,并将errno设置为EIDRM。而对于P...
  • 五、Linux--信号量

    2016-12-03 14:33:31
    查看系统当前的信号量: 利用ipcs命令显示semaphore arrays    ipcrm -s semid 删除“semid” 头文件:#include #include #include 函数原型:int semget(key_t key, int nsems, int ...
  • unix/linux下的共享内存、信号量、队列信息管理 在unix/linux下,经常有因为共享内存、信号量,队列等共享信息没有干净地清楚而引起一些问题。 查看共享信息的内存的命令是ipcs...-m 删除共享内存,-s删除共享信号量...
  • 删除创建的信号量:ipcrm -S key 1.创建信号量集 semget函数: int semget(key_t key, //id int nsems,//信号量集中有几个信号量 打开写0 int semflg);//IPC_CREAT|0644 打开0 代码实现为: ...
  • 如果不删除信号量,它将继续在系统中存在,即使程序已经退出,它可能在你下次运行此程序时引发问题,而且信号量是一种有限的资源。 简单的例子 父进程与子进程共享打印机,必须其中一者打印完后,另一者再打印。 ...
  • 申请信号量集 ==》pv操作 ===》卸载删除信号量集 semget() semop() semctl() 1、申请信号量 #include <sys/sem.h> int semget(key_t key, int nsems, int semflg); 功能:该函数可以使用特定的key向内核提出...
  • 信号量相关的函数5.1 创建信号量5.2 删除和初始化信号量5.3 改变信号量的值5.4 sembuf中sem_flg的设置问题6.信号量实现进程间同步 1. 信号量 产生背景: 多个程序同时访问一个共享资源可能会引发一系列问题,所以...
  • 文章目录一、信号量简介二、信号量函数1.semget 创建/获取信号量2.semop 修改信号量值(p v)3.semctl 初始化、删除三、demo 父子进程的信号量 一、信号量简介 在对于临界区资源管理的过程中,多个程序同时访问一个...
  • 跟posix消息队列,共享内存的打开,关闭,删除操作一样,不过,上面的函数是对有名信号量进行操作,通过man帮助可以得知: 有名信号量相对的那就是无名信号量,对于它相关的函数如下: 同样可以查看man帮助: ...
  • 查看系统中已创建的信号量命令: ipcs -s:sdc@sdc-vm:~/product/linux-ipc/build$ ipcs -s ​ --------- 信号量数组 ----------- 键 semid 拥有者 权限 nsems 0x01011cf6 1802240 sdc 666 1 ...
  • Linux下进程间通信的方法--信号量

    千次阅读 2015-02-09 01:16:29
    这里的信号量主要是在不同的...并且可以通过semctl调用command设置为IPC_RMID来删除信号量ID: 因为库里没有定义union semun,因此需要自己定义.用到信号量的三个函数 semget 用来创建一个新信号量或者取得一个已有信号
  • 通过一个可选的参数来指定程序是负责创建信号量还是负责删除信号量。 用两个不同字符的输出来表示进入和离开临界区域。如果程序启动时带有一个参数,它将在进入和退出临界区域时打印字符X;而程序的其
  • 2. 在Linux操作系统上,利用Pthread API提供的信号量机制,编写应用程序实现生产者——消费者问题。 3. 两种环境下,生产者和消费者均作为独立线程,并通过empty、full、mutex三个信号量实现对缓冲进行插入与删除。...
  • 线程信号量进程信号量与线程信号量二值信号量和多值信号量信号量的使用步骤...wait的兄弟函数v操作函数原型功能返回值pv操作实现互斥图解说明删除信号量函数原型功能使用信号量实现互斥代码演示使用线程信号量,实现...
  • 转载自:http://linuxperf.com/?p=25 对原文做了一些删减和结构上的优化。 SystemV 信号量 SystemV 信号量是内核对象,由内核统一管理...semctl(2): 删除信号量。(进程即使不存在,信号量也存在于内核中,除非调用此函
  • 在unix/linux下,经常有因为共享内存、信号量,队列等共享信息没有干净地清楚而引起一些问题。查看共享信息的内存的命令是ipcs [-m|-s|-q]。 默认会列出共享内存、信号量,队列信息,-m列出共享内存,-s列出共享...
  • Linux中有多种类型的信号量,其中SystemV是比较重要的一种,常用于多进程同步和进程间通信。...自己写了一个程序,两个进程分别向控制台打印字符串,两个进程几乎一样,只是B进程中没有初始化/删除信号量
  • 1、相似点每个内核中的IPC结构(消息队列、信号量、共享存储)都用一个非负整数的标识符加以引用,与文件描述符不同,当一个IPC结构被创建,以后又被删除时,与这种结构相关的标识符连续加1,直至达到一个整型数的...
  • system v 的IPC对象有共享内存、信号量、消息队列。在linux下可以使用IPC对象进程进程间通信。IPC对象存在于内核中,作为桥梁供多进程操作进行数据通信。 注意:IPC对象的作用范围是整个系统内,因此创建IPC对象当...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 219
精华内容 87
关键字:

linux删除信号量

linux 订阅