zoukankan      html  css  js  c++  java
  • 进程同步与相互排斥:POSIX有名信号量

    在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量。

    无名信号量一般用于线程间同步或相互排斥,而有名信号量一般用于进程间同步或相互排斥

    它们的差别和管道及命名管道的差别类似。无名信号量则直接保存在内存中,而有名信号量要求创建一个文件。前面我们学习了无名信号量的使用(详情请看《无名信号量》)。这里我们学习有名信号量的使用。


    1)创建一个有名信号量

    所需头文件:

    #include <fcntl.h>

    #include <sys/stat.h>

    #include <semaphore.h>


    当有名信号量存在时使用:
    sem_t *sem_open(const char *name, int oflag);


    当有名信号量不存在时使用:
    sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

    功能:

    创建一个有名信号量。

    參数:

    name:信号量文件名称。注意,不能指定路径名。由于有名信号量,默认放在/dev/shm 里。例如以下图:

    flags:sem_open() 函数的行为标志。

    mode:文件权限(可读、可写、可运行)的设置。

    value:信号量初始值。

    返回值:

    成功:信号量的地址

    失败:SEM_FAILED


    2)关闭有名信号量

    所需头文件:

    #include <semaphore.h>


    int sem_close(sem_t *sem);
    功能:

    关闭有名信号量。

    參数:

    sem:指向信号量的指针。

    返回值:

    成功:0

    失败:-1


    3)删除有名信号量文件

    所需头文件:

    #include <semaphore.h>


    int sem_unlink(const char *name);
    功能:

    删除有名信号量的文件。

    參数:

    name:有名信号量文件名称。

    返回值:

    成功:0

    失败:-1


    4)信号量 PV 操作

    使用方法和《POSIX 无名信号量》一样,详情请点此链接。


    有名信号量实现进程间相互排斥功能:

    1. #include<stdio.h>  
    2. #include<semaphore.h>  
    3. #include<fcntl.h>  
    4. #include<unistd.h>  
    5. #include<sys/stat.h>  
    6. #include<sys/types.h>  
    7.   
    8. void printer(sem_t *sem, char *str)  
    9. {  
    10.     sem_wait(sem);  //信号量减一  
    11.     while(*str!='')  
    12.     {  
    13.         putchar(*str);    
    14.         fflush(stdout);  
    15.         str++;  
    16.         sleep(1);  
    17.     }  
    18.     printf(" ");   
    19.       
    20.     sem_post(sem);  //信号量加一  
    21. }  
    22.   
    23. int main(int argc, char *argv[])  
    24. {  
    25.     pid_t pid;  
    26.     sem_t *sem = NULL;  
    27.       
    28.     pid = fork(); //创建进程  
    29.     if(pid<0){ //出错  
    30.         perror("fork error");  
    31.           
    32.     }else if(pid == 0){ //子进程  
    33.       
    34.         //跟open()打开方式非常相似,不同进程仅仅要名字一样。那么打开的就是同一个有名信号量  
    35.         sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1); //信号量值为 1  
    36.         if(sem == SEM_FAILED){ //有名信号量创建失败  
    37.             perror("sem_open");  
    38.             return -1;  
    39.         }  
    40.           
    41.         char *str1 = "hello";  
    42.         printer(sem, str1); //打印  
    43.           
    44.         sem_close(sem); //关闭有名信号量  
    45.           
    46.         _exit(1);  
    47.     }else if(pid > 0){ //父进程  
    48.           
    49.         //跟open()打开方式非常相似,不同进程仅仅要名字一样,那么打开的就是同一个有名信号量  
    50.         sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1); //信号量值为 1  
    51.         if(sem == SEM_FAILED){//有名信号量创建失败  
    52.             perror("sem_open");  
    53.             return -1;  
    54.         }  
    55.           
    56.         char *str2 = "world";  
    57.         printer(sem, str2); //打印  
    58.           
    59.         sem_close(sem); //关闭有名信号量  
    60.           
    61.         wait(pid, NULL); //等待子进程结束  
    62.     }  
    63.       
    64.     sem_unlink("name_sem");//删除有名信号量  
    65.       
    66.     return 0;  
    67. }  

    执行结果例如以下:


    有名信号量实现进程间同步功能(print2 先打印。再到 print1 打印):

    print1.c 代码例如以下:

    1. #include <fcntl.h>           /* For O_* constants */  
    2. #include <sys/stat.h>        /* For mode constants */  
    3. #include <semaphore.h>  
    4. #include <stdio.h>  
    5.   
    6. void print(sem_t *print1, sem_t *print2)  
    7. {  
    8.     int i = 0;  
    9.     while(1)  
    10.     {  
    11.         sem_wait(print1);  
    12.         i++;  
    13.         printf("int print1 i = %d ", i);  
    14.         sem_post(print2);  
    15.     }  
    16. }  
    17.   
    18. int main(int argc, char **argv)  
    19. {     
    20.     sem_t *print1, *print2;  
    21.   
    22.     print1 = sem_open("sem_print1", O_CREAT, 0777, 0);    
    23.     if(SEM_FAILED == print1)  
    24.     {  
    25.         perror("sem_open");  
    26.     }  
    27.       
    28.     print2 = sem_open("sem_print2", O_CREAT, 0777, 1);      
    29.     if(SEM_FAILED == print2)  
    30.     {  
    31.         perror("sem_open");  
    32.     }  
    33.       
    34.     print(print1, print2);  
    35.       
    36.     return 0;  
    37. }  

    print2.c 代码例如以下:
    1. #include <fcntl.h>           /* For O_* constants */  
    2. #include <sys/stat.h>        /* For mode constants */  
    3. #include <semaphore.h>  
    4. #include <stdio.h>  
    5.   
    6. void print(sem_t *print1, sem_t *print2)  
    7. {  
    8.     int i = 0;  
    9.     while(1)  
    10.     {  
    11.         sem_wait(print2);  
    12.         i++;  
    13.         printf("in print2 i = %d ", i);  
    14.         sleep(1);  
    15.         sem_post(print1);  
    16.     }  
    17. }  
    18.   
    19. int main(int argc, char **argv)  
    20. {     
    21.     sem_t *print1, *print2;  
    22.       
    23.     print1 = sem_open("sem_print1", O_CREAT, 0777, 0);    
    24.     if(SEM_FAILED == print1)  
    25.     {  
    26.         perror("sem_open");  
    27.     }  
    28.       
    29.     print2 = sem_open("sem_print2", O_CREAT, 0777, 1);    
    30.     if(SEM_FAILED == print2)  
    31.     {  
    32.         perror("sem_open");  
    33.     }  
    34.       
    35.     print(print1, print2);  
    36.       
    37.     return 0;  
    38. }  

    删除有名信号量演示样例代码例如以下:
    1. #include <semaphore.h>  
    2. #include <stdio.h>  
    3.   
    4. void sem_del(char *name)  
    5. {  
    6.     int ret;  
    7.   
    8.     ret = sem_unlink(name);  
    9.     if(ret < 0)  
    10.     {  
    11.         perror("sem_unlink");  
    12.     }  
    13. }  
    14.   
    15. int main(int argc, char **argv)  
    16. {  
    17.     sem_del("sem_print1"); //删除信号量文件sem_print1  
    18.     sem_del("sem_print2"); //删除信号量文件sem_print2  
    19.       
    20.     return 0;  
    21. }  

    makefile 代码例如以下:
    [plain] view plaincopy
    1. all:  
    2.     gcc sem_del.c -o sem_del -lpthread  
    3.     gcc print1.c -o print1 -lpthread  
    4.     gcc print2.c -o print2 -lpthread  
    5. clean:  
    6.     rm sem_del print1 print2  

    执行程序时。先把有名信号量删除(sem_del)。再分别执行 print1 和 print2:




    本教程演示样例代码下载请点此处。


     转自:http://blog.csdn.net/tennysonsky/article/details/46500417

  • 相关阅读:
    星空Password
    股票交易
    【1】博客目录
    事务
    C#基础索引
    C# String
    MSIL
    Evaluation Stack
    Spring源码编译以及导入Intellij IDEA的操作步骤
    WebFlux响应式编程简单示例
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/6852669.html
Copyright © 2011-2022 走看看