zoukankan      html  css  js  c++  java
  • linux Posix 信号量 一

    信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语。

    linux提供两种信号量,“内核信号量”和“用户态进程信号量”,“用户态信号量”又分为“Posix”,“System V”信号量。

    今天我们主要讲解Posix信号量,Posix分为 有名/无名(又称匿名/内存信号量):

    1、Posix有名信号量,使用Posix IPC名字标识;

    2、Posix匿名信号量,基于内存的信号量,存放在共享内存区中;

      无名信号量常用于多线程间的同步,同时也用于相关进程间的同步。也就是说,无名信号量必须是多个进程(线程)的共享变量,无名信号量要保护的变量也必须是多个进程(线程)的共享变量,这两个条件是缺一不可的。

    图1 由两个进程使用的一个二值信号量

    图2 由两个进程使用的一个Posix有名二值信号量

    图3 由一个进程内的两个线程共享的基于内存的信号量

    一个进程可以在某个信号量上执行的三种操作:

    1、创建一个信号量,这要求调用者指定初始值,对于二值信号量来说,它通常是1,也可是0。

    2、等待一个信号量,该操作会测试这个信号量的值,如果小于0,就阻塞。也称为P操作。

    3、挂出一个信号量,该操作将信号量的值加1,也称为V操作。

    信号量、互斥锁和条件变量之间的三个差异:

    1、互斥锁必须总是给它上锁的线程解锁,信号量的挂出却不必由执行过它的等待操作的同一线程执行。

    2、互斥锁要么被锁住,要么被解开。

    3、既然信号量有一个与之关联的状态,那么信号量挂出操作总是被记住。然而当向一个条件变量发送信号时,如果没有线程等待在该条件变量上,信号丢失。

    Posix提供两类信号量:有名信号量和基于内存的信号量(也称无名信号量)。使用函数如下:

     
    1. #include <semaphore.h>  
    2. /*sem_open创建一个新的有名信号量或打开一个已存在的有名信号量,value参数指定信号量的初始值,返回值是一个指向某个sem_t数据类型的指针,用作其他函数的参数*/  
    3. sem_t   *sem_open(const char *name, int oflag, .../*mode_t mode, unsigned int value*/);  
    4. int sem_close(sem_t *sem); /*一个进程终止时,内核对其上仍打开着的所有信号量自动执行关闭操作*/  
    5. int     sem_unlink(const char *name); /*sem_unlink函数:当引用计数大于0时,name就能从文件系统中删除,然而信号量的析构却要等到最后一个sem_close发生时为止*/  
    6. int     sem_wait(sem_t *sem); /*测试所指定信号量的值,大于0,将它减1并返回,等于0,调用线程休眠,直到该值大于0,将它减1,函数随后返回*/  
    7. int     sem_trywait(sem_t *sem); /*所指定信号量值为0时,不休眠,而是返回一个EAGAIN错误*/  
    8. int     sem_post(sem_t *sem);  
    9. int     sem_getvalue(sem_t *sem, int  *valp);/* 由valp指向的整数中返回所指定信号量的当前值。*/  

    semcreate程序: 

    1. #include <semaphore.h>  
    2. #include <stdio.h>  
    3. #include <stdlib.h>  
    4. #include <unistd.h>  
    5. #include <fcntl.h>  
    6. #include <sys/stat.h>  
    7. #include <sys/types.h>  
    8.   
    9. #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)  
    10.   
    11. int  
    12. main(int argc, char **argv)  
    13. {  
    14.     int     c, flags;  
    15.     sem_t   *sem;  
    16.     unsigned int value;  
    17.   
    18.     flags = O_RDWR | O_CREAT;  
    19.     value = 1;  
    20.   
    21.     while((c = getopt(argc, argv, "ei:")) != -1){  
    22.         switch(c){  
    23.             case 'e':  
    24.                 flags |= O_EXCL;  
    25.             case 'i':  
    26.                 value = atoi(optarg);  
    27.                 break;    
    28.         }     
    29.     }  
    30.   
    31.     if(optind != argc - 1){  
    32.         printf("usage:semcreate [-e] [-i initalvalue] <name> ");   
    33.         return -1;  
    34.     }  
    35.     sem = sem_open(argv[optind], flags, FILE_MODE, value);  
    36.   
    37.     sem_close(sem);  
    38.     exit(0);  
    39. }  

    semunlink程序:

    1. #include <semaphore.h>  
    2. #include <stdio.h>  
    3. #include <stdlib.h>  
    4. #include <unistd.h>  
    5.   
    6. int  
    7. main(int argc, char **argv)  
    8. {  
    9.     if(argc != 2){  
    10.         printf("usage:semunlink <name>. ");    
    11.         return -1;  
    12.     }  
    13.   
    14.     sem_unlink(argv[1]);  
    15.     exit(0);  
    16. }  

    semgetvalue程序:

     
    1. #include <semaphore.h>  
    2. #include <stdio.h>  
    3. #include <stdlib.h>  
    4. #include <unistd.h>  
    5.   
    6. int  
    7. main(int argc, char **argv)  
    8. {  
    9.     sem_t   *sem;  
    10.     int     val;  
    11.   
    12.     if(argc != 2){  
    13.         printf("usage:semgetvalue <name>. ");      
    14.         return -1;  
    15.     }  
    16.   
    17.     sem = sem_open(argv[1], 0);  
    18.     sem_getvalue(sem, &val);  
    19.     printf("value = %d ", val);  
    20.   
    21.     exit(0);  
    22. }  

    semwait程序:

     

    1. #include <semaphore.h>  
    2. #include <stdio.h>  
    3. #include <stdlib.h>  
    4. #include <unistd.h>  
    5.   
    6. int  
    7. main(int argc, char **argv)  
    8. {  
    9.     sem_t   *sem;  
    10.     int     val;  
    11.   
    12.     if(argc != 2){  
    13.         printf("usage: semwait <name>");    
    14.         return -1;  
    15.     }  
    16.   
    17.     sem = sem_open(argv[1], 0);  
    18.     sem_wait(sem);  
    19.     sem_getvalue(sem, &val);  
    20.     printf("pid %ld has semaphore, value = %d ", (long)getpid(), val);  
    21.   
    22.     pause();                /*block until killed*/  
    23.     exit(0);  
    24. }  

    sempost程序:


     

    1. #include <semaphore.h>  
    2. #include <stdio.h>  
    3. #include <stdlib.h>  
    4. #include <unistd.h>  
    5.   
    6. int  
    7. main(int argc, char **argv)  
    8. {  
    9.     sem_t   *sem;  
    10.     int     val;  
    11.   
    12.     if(argc != 2){  
    13.         printf("usage:sempost <name> ");   
    14.         return -1;  
    15.     }  
    16.   
    17.     sem = sem_open(argv[1], 0);  
    18.     sem_post(sem);  
    19.     sem_getvalue(sem, &val);  
    20.     printf("value = %d ", val);  
    21.   
    22.     exit(0);  
    23. }  

    Posix基于内存的信号量,由应用程序分配信号量的内存空间(也就是分配一个sem_t数据类型的内存空间),然后由系统初始化它们的值。


     

    1. #include <stmaphore.h>  
    2. int sem_init(sem_t *sem, int shared, unsigned int value);  /*出错返回-1*/  
    3. int     sem_destroy(sem_t *sem);            <span style="white-space:pre">    </span>/*成功返回0,出错返回-1*/  

    基于内存的信号量是由sem_init初始化的,sem参数指向应用程序必须分配的sem_t变量。如果shared为0,那么待初始化的信号量是在同一进程的各个线程间共享的,否则该信号量是在进程间共享的。

    当不需要使用与有名信号量关联的名字时,可改用基于内存的信号量。彼此无亲缘关系的不同进程需要使用信号量时,通常使用有名信号量。其名字就是各个进程标识信号量的手段。基于内存信号量至少具有进程持续性,然而它们真正的持续性却取决于存放信号量的内存区的类型。只要含有某个基于内存信号量的内存区保持有效,该信号量就一直存在。

    进程间共享信号量

    进程间共享基于内存信号量的规则很简单:信号量本身必须驻留在由所有希望共享它的进程所共享的内存区中,而且sem_init的第二个参数必须是1。

    有名信号量,不同进程总是能够访问同一个有名信号量,只要它们在调用sem_open时指定相同的名字即可。

    信号量限制

    Posix定义了两个信号量限制:

    SEM_NSEMS_MAX 一个进程可同时打开着的最大信号数

    SEM_VALUE_MAX 一个信号量的最大值

    这两个常值定义在<unistd.h>头文件中,可在运行时通过sysconf函数获取。

  • 相关阅读:
    Github挂载大文件解决方案
    UWP 更强大的文件获取能力
    UWP 打开系统设置面板
    Windows 10
    Flutter
    Android笔记(三):View一些值得注意的地方
    Android笔记(二):savedIndstanceState 和 Bundle
    Android笔记(一):this 的表示范围和 Context
    用atom写LaTeX文档
    博客园LaTeX数学公式功能及效果展示
  • 原文地址:https://www.cnblogs.com/jiangzhaowei/p/4201972.html
Copyright © 2011-2022 走看看