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