Linux 多任務編程——進程同步與互斥: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 無名信號量》一樣。

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

#include<stdio.h>
#include<semaphore.h>
#include<fcntl.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
 
void printer(sem_t *sem, char *str)
{
    sem_wait(sem);    //信號量減一
    while(*str!='\0')
    {
        putchar(*str);    
        fflush(stdout);
        str++;
        sleep(1);
    }
    printf("\n"); 
    
    sem_post(sem);    //信號量加一
}
 
int main(int argc, char *argv[])
{
    pid_t pid;
    sem_t *sem = NULL;
    
    pid = fork(); //創建進程
    if(pid<0){ //出錯
        perror("fork error");
        
    }else if(pid == 0){ //子進程
    
        //跟open()打開方式很相似,不同進程只要名字一樣,那麼打開的就是同一個有名信號量
        sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1); //信號量值爲 1
        if(sem == SEM_FAILED){ //有名信號量創建失敗
            perror("sem_open");
            return -1;
        }
        
        char *str1 = "hello";
        printer(sem, str1); //打印
        
        sem_close(sem); //關閉有名信號量
        
        _exit(1);
    }else if(pid > 0){ //父進程
        
        //跟open()打開方式很相似,不同進程只要名字一樣,那麼打開的就是同一個有名信號量
        sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1); //信號量值爲 1
        if(sem == SEM_FAILED){//有名信號量創建失敗
            perror("sem_open");
            return -1;
        }
        
        char *str2 = "world";
        printer(sem, str2); //打印
        
        sem_close(sem); //關閉有名信號量
        
        wait(pid, NULL); //等待子進程結束
    }
    
    sem_unlink("name_sem");//刪除有名信號量
    
    return 0;
}

運行結果如下:

 

有名信號量實現進程間同步功能(print2 先打印,再到 print1 打印):

print1.c 代碼如下:

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
#include <stdio.h>
 
void print(sem_t *print1, sem_t *print2)
{
    int i = 0;
    while(1)
    {
        sem_wait(print1);
        i++;
        printf("int print1 i = %d\n", i);
        sem_post(print2);
    }
}
 
int main(int argc, char **argv)
{    
    sem_t *print1, *print2;
 
    print1 = sem_open("sem_print1", O_CREAT, 0777, 0);  
    if(SEM_FAILED == print1)
    {
        perror("sem_open");
    }
    
    print2 = sem_open("sem_print2", O_CREAT, 0777, 1);    
    if(SEM_FAILED == print2)
    {
        perror("sem_open");
    }
    
    print(print1, print2);
    
    return 0;
}

print2.c 代碼如下:

#include <fcntl.h>           /* For O_* constants */
#include <sys/stat.h>        /* For mode constants */
#include <semaphore.h>
#include <stdio.h>
 
void print(sem_t *print1, sem_t *print2)
{
    int i = 0;
    while(1)
    {
        sem_wait(print2);
        i++;
        printf("in print2 i = %d\n", i);
        sleep(1);
        sem_post(print1);
    }
}
 
int main(int argc, char **argv)
{    
    sem_t *print1, *print2;
    
    print1 = sem_open("sem_print1", O_CREAT, 0777, 0);  
    if(SEM_FAILED == print1)
    {
        perror("sem_open");
    }
    
    print2 = sem_open("sem_print2", O_CREAT, 0777, 1);  
    if(SEM_FAILED == print2)
    {
        perror("sem_open");
    }
    
    print(print1, print2);
    
    return 0;
}

 

刪除有名信號量示例代碼如下:

#include <semaphore.h>
#include <stdio.h>
 
void sem_del(char *name)
{
    int ret;
 
    ret = sem_unlink(name);
    if(ret < 0)
    {
        perror("sem_unlink");
    }
}
 
int main(int argc, char **argv)
{
    sem_del("sem_print1"); //刪除信號量文件sem_print1
    sem_del("sem_print2"); //刪除信號量文件sem_print2
    
    return 0;
}

 

makefile 代碼如下:

all:
    gcc sem_del.c -o sem_del -lpthread
    gcc print1.c -o print1 -lpthread
    gcc print2.c -o print2 -lpthread
clean:
    rm sem_del print1 print2

 

運行程序時,先把有名信號量刪除(sem_del),再分別運行 print1 和 print2:

 


--------------------- 
作者:Mike__Jiang 
來源:CSDN 
原文:https://blog.csdn.net/tennysonsky/article/details/46500417 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章