Linux信號量詳解


1.什么是信號量
信號量是一種特殊的變量,訪問具有原子性。
只允許對它進行兩個操作:
1)等待信號量
當信號量值為0時,程序等待;當信號量值大於0時,信號量減1,程序繼續運行。
2)發送信號量
將信號量值加1。

我們使用信號量,來解決進程或線程間共享資源引發的同步問題。

2.Linux中信號量的使用
Linux提供了一組信號量API,聲明在頭文件sys/sem.h中。
1)semget函數:新建信號量

int semget(key_t key,int num_sems,int sem_flags);

key:信號量鍵值,可以理解為信號量的唯一性標記。
num_sems:信號量的數目,一般為1
sem_flags:有兩個值,IPC_CREATE和IPC_EXCL,
IPC_CREATE表示若信號量已存在,返回該信號量標識符。
IPC_EXCL表示若信號量已存在,返回錯誤。

返回值:相應的信號量標識符,失敗返回-1

2)semop函數:修改信號量的值

int semop(int sem_id,struct sembuf *sem_opa,size_t num_sem_ops);

sem_id:信號量標識符
sem_opa:結構如下

struct sembuf{  
    short sem_num;//除非使用一組信號量,否則它為0  
    short sem_op;//信號量在一次操作中需要改變的數據,通常是兩個數,一個是-1,即P(等待)操作,  
                    //一個是+1,即V(發送信號)操作。  
    short sem_flg;//通常為SEM_UNDO,使操作系統跟蹤信號,  
                    //並在進程沒有釋放該信號量而終止時,操作系統釋放信號量  
}; 

3)semctl函數:用於信號量的初始化和刪除

int semctl(int sem_id,int sem_num,int command,[union semun sem_union]);

command:有兩個值SETVAL,IPC_RMID,分別表示初始化和刪除信號量。
sem_union:可選參數,結構如下:

union semun{  
    int val; 
    struct semid_ds *buf;  
    unsigned short *arry;  
}; 

一般用到的是val,表示要傳給信號量的初始值。

3.Linux信號量使用示例
下例中,我們寫了一個程序,程序中有一個char類型的字符,char message='x'
然后同時運行這個程序的兩個實例。
第一個實例,帶一個參數,將參數的第一個字符賦給message,比如為'0'
第二個實例,使用默認message值'x'
我們的目的是,使用信號量,循環執行這兩個實例,
我們可以看到執行結果應該是'x0x0x0x0x0x0'

#include<stdio.h>
#include<stdlib.h>
#include<sys/sem.h>
union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};
int sem_id;
int set_semvalue()
{
    union semun sem_union;    
    sem_union.val = 1;
    if(semctl(sem_id,0,SETVAL,sem_union)==-1)
        return 0;
    return 1;
}
int semaphore_p()
{
    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)
    {
        fprintf(stderr,"semaphore_p failed\n");
        return 0;
    }
    return 1;
}
int semaphore_v()
{
    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)
    {
        fprintf(stderr,"semaphore_v failed\n");
        return 0;
    }
    return 1;
}
void del_semvalue()
{
    //刪除信號量
    union semun sem_union;
    if(semctl(sem_id,0,IPC_RMID,sem_union)==-1)
        fprintf(stderr,"Failed to delete semaphore\n");
}
int main(int argc,char *argv[])
{
    char message = 'x';
    //創建信號量
     sem_id = semget((key_t)1234,1,0666|IPC_CREAT);
    if(argc>1)
    {
        //初始化信號量
        if(!set_semvalue())
        {
            fprintf(stderr,"init failed\n");
            exit(EXIT_FAILURE);
        }
        //參數的第一個字符賦給message
        message = argv[1][0];
    }
    int i=0;
    for(i=0;i<5;i++)
    {
        //等待信號量
        if(!semaphore_p())
            exit(EXIT_FAILURE);
        printf("%c",message);
        fflush(stdout);
        sleep(1);
        //發送信號量
        if(!semaphore_v())
            exit(EXIT_FAILURE);
        sleep(1);
    }
    printf("\n%d-finished\n",getpid());
    if(argc>1)
    {
        //退出前刪除信號量
        del_semvalue();
    }
    exit(EXIT_SUCCESS);
}

輸出結果:


免責聲明!

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



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