有名信號量


在 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 操作

有名信號量實現進程間互斥功能:

 
  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!='\0')  
  12.     {  
  13.         putchar(*str);    
  14.         fflush(stdout);  
  15.         str++;  
  16.         sleep(1);  
  17.     }  
  18.     printf("\n");   
  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\n", 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\n", 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 代碼如下:


  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:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM