1. 程式人生 > >Posix訊號量基本知識

Posix訊號量基本知識

1. 引言

訊號量包含一個非負整型變數,其包含一對原子操作,即P/V操作。

P操作:若訊號量非負,則P操作將訊號量值減1;若訊號量為0,則P操作將執行wait操作。

V操作:將訊號量值加1。

Linux包含兩類訊號量:

訊號量可分為Posix訊號量和System V訊號量。今天我們主要學習一下Posix訊號量,其有兩類形式:命名訊號量和無名訊號量,其主要區別在於建立和銷燬的形式。命名訊號量:可以通過名字訪問,因此可用於知道他們名字的任意程序和執行緒使用。無名訊號量:只存在於記憶體中,並要求使用訊號量的程序可以訪問記憶體,這意味著他們只能應用在同一程序中執行緒,或者不同程序的共享記憶體上。以下我們介紹的介面都在標頭檔案<semaphore.h>中。

2. 無名訊號量

2.1 初始化

#include <semaphore.h>
int sem_init(sem_t *sem, int pshared,unsigned int value);
sem :訊號量變數;

pshared:表明是否在多個程序中使用訊號量,如果是則應該傳遞非0值;

value:該引數指定訊號量的初始值。如果想要在兩個程序之間使用訊號量,需要確保sem引數指向兩個程序之間共享的記憶體範圍。


2.2 銷燬

#include <semaphore.h>
int sem_destroy(sem_t *sem);
3. 命名訊號量

3.1 初始化

#include <semaphore.h>
sem_t *sem_open(const char *name, int oflag, /* mode_t mode, unsigned int value */);
我們可以呼叫該函式建立或者開啟一個訊號量,成功返回訊號量的指標,不成功返回SEM_FAILED。但oflag引數中指定O_CREAT標誌集時,若訊號量不存在則建立一個新的。mode引數指定誰可以訪問訊號量,其取值與開啟檔案的許可權位相同,該許可權可以被呼叫者的檔案建立遮蔽字修改。value引數用來指定訊號量的初始值,範圍在0 ~ SEM_VALUE_MAX之間。

3.2 關閉與銷燬

int sem_close(sem_t *sem);
int sem_unlink(const char *name);
sem_close函式:用於釋放任何訊號量相關的資源。當一個程序退出時,核心將自動關閉任何開啟的訊號量,但這並影響訊號量的狀態,其他程序仍舊會根據當前狀態使用。使用sem_close也是同樣道理。

sem_unlink函式,用來銷燬一個命名訊號量。與上一個函式不同,該函式用於刪除訊號量的名字,如果沒有開啟的訊號量引用,則該訊號量會被銷燬,否則延遲到最後一個開啟的引用關閉。

4. 通用操作

4.1 P操作

#include <semaphore.h>
int sem_trywait(sem_t *sem);
int sem_wait(sem_t *sem);
這兩個函式可實現訊號量的減1操作,但訊號量技術計數為0,sem_wait會阻塞,直到成功使訊號量減1或者被訊號中斷時才返回。而sem_trywait為非阻塞版本,當訊號量為0時,該函式返回-1並且將errno置為EAGAIN。還有第三個選擇,即一個帶有超時的版本。
#include <semaphore.h>
#include <time.h>
int sem_timedwait(sem_t * sem, const struct timespec time);
如果超時到期並且訊號量計數沒能減1,sem_timedwait將返回-1且將errno設定為ETIMEDOUT。

4.2 V操作

#include <semaphore.h>
int sem_post(sem_t *sem);
該函式將訊號量加1,若此時有sem_wait正在阻塞則喚醒。

4.3 取值操作

#include<semaphore.h>
int sem_t getvalue(sem_t sem, int *val);
該函式用於獲取訊號量的值,一般只用來除錯。

5. 簡單例項

#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdio.h>  

#define MAX 100;

sem_t *sem1,*sem2;    

void* thread_func_1(void* arg)
{
    int i;
    for(i = 0; i < MAX; ++i)
    {
        sem_wait(&sem1);
        printf("number in thread1 is %d\n",i);
        sem_post(&sem2);    
    }
    pthread_exit((void*)"thread1 exit\n");

}

void* thread_func_2(void* arg)
{    
    int i; 
    for(i = 0; i < MAX; ++i)
    {        
        sem_wait(&sem2);
        printf("number in thread2 is %d\n",i);
        sem_post(&sem1);
    }  
    pthread_exit((void*)"thread2 exit\n"); 
}

int main(void)
{   
       
void* ret;  
sem_init(sem1,0,5);
sem_init(sem2,0,5);
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,<span style="font-family: Arial, Helvetica, sans-serif;">thread_func_1</span>,NULL);           
pthread_create(&tid2,NULL,<span style="font-family: Arial, Helvetica, sans-serif;">thread_func_2</span>,NULL); 
       
pthread_join(tid1,&ret); //ret = "thread1 exit"      
pthread_join(tid2,&ret); //ret = "thread2 exit"       
sem_destroy(&sem1);        
sem_destroy(&sem2);  
       
return 0;

}