程序間通訊 POSIX 有名訊號量與無名訊號量

2021-09-11 13:25:45 字數 4663 閱讀 7758

在 posix 系統中,程序間通訊是乙個很有意思的話題。

posix訊號量程序是3種 ipc(inter-process communication) 機制之一,3種 ipc 機制源於 posix.1 的實時擴充套件。single unix specification 將3種機制(訊息佇列,訊號量和共享儲存)置於可選部分中。在 susv4 之前,posix 訊號量介面已經被包含在訊號量選項中。在 susv4 中,這些介面被移至了基本規範,而訊息佇列和共享儲存介面依然是可選的。

posix 訊號量介面意在解決 xsi 訊號量介面的幾個缺陷。

前段時間筆者在寫管道通訊的時候,**了一下 posix 程序間的兩種訊號量通訊方式:有名訊號量和無名訊號量。有很多人認為程序間通訊只能使用有名訊號量,無名訊號量只能用於單程序間的多執行緒通訊。其實無名訊號量也可以進行程序間通訊。

有名訊號量和無名訊號量的差異在於建立和銷毀的形式上,但是其他工作一樣。

無名訊號量只能存在於記憶體中,要求使用訊號量的程序必須能訪問訊號量所在的這一塊記憶體,所以無名訊號量只能應用在同一程序內的執行緒之間(共享程序的記憶體),或者不同程序中已經對映相同記憶體內容到它們的位址空間中的執行緒(即訊號量所在記憶體被通訊的程序共享)。意思是說無名訊號量只能通過共享記憶體訪問。

相反,有名訊號量可以通過名字訪問,因此可以被任何知道它們名字的程序中的執行緒使用。

單個程序中使用 posix 訊號量時,無名訊號量更簡單。多個程序間使用 posix 訊號量時,有名訊號量更簡單。

無論是有名訊號量還是無名訊號量,都可以通過以下函式進行訊號量值操作。

weit 為訊號量值減一操作,總共有三個函式,函式原型如下:

#include 

int sem_wait(sem_t *sem);

int sem_trywait(sem_t *sem);

int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

link with -pthread.這一句表示 gcc 編譯時,要加 -pthread.返回值:若成功,返回 0 ;若出錯,返回-1

複製**

其中,第乙個函式的作用是,若 sem 小於 0 ,則執行緒阻塞於訊號量 sem ,直到 sem 大於 0 ;否則訊號量值減1。

第二個函式作用與第乙個相同,只是此函式不阻塞執行緒,如果 sem 小於 0,直接返回乙個錯誤(錯誤設定為 eagain )。

第三個函式作用也與第乙個相同,第二個引數表示阻塞時間,如果 sem 小於 0 ,則會阻塞,引數指定阻塞時間長度。 abs_timeout 指向乙個結構體,這個結構體由從1970-01-01 00:00:00 +0000 (utc)開始的秒數和納秒數構成。結構體定義如下:

struct timespec ;

複製**

如果指定的阻塞時間到了,但是 sem 仍然小於 0 ,則會返回乙個錯誤 (錯誤設定為 etimedout )。

post 為訊號量值加一操作,函式原型如下:

#include 

int sem_post(sem_t *sem);

link with -pthread.返回值:若成功,返回 0 ;若出錯,返回-1

複製**

建立

有名訊號量建立可以呼叫sem_open函式,函式說明如下:

#include 

sem_t *sem_open(const char *name, int oflag);

sem_t *sem_open(const char *name, int oflag,

mode_t mode, unsigned int value);

link with -pthread.返回值:若成功,返回指向訊號量的指標;若出錯,返回sem_falled

複製**

其中第一種函式是當使用已有的有名訊號量時呼叫該函式,flag 引數設為0

如果要呼叫第二種函式,flag 引數應設為o_creat,如果有名訊號量不存在,則會建立乙個新的,如果存在,則會被使用並且不會再初始化。

當我們使用o_creat標誌時,需要提供兩個額外的引數:

mode 引數指定誰可以訪問訊號量,即許可權組,mode 的取值和開啟檔案的許可權位相同,比如0666表示所有使用者可讀寫。因為只有讀和寫訪問要緊,所以實現經常為讀和寫開啟訊號量。

value 指定訊號量的初始值,取值範圍為 0~sem_value_max 。

如果訊號量存在,則呼叫第二個函式會忽略後面兩個引數(即 mode 和 value )。

釋放當完成訊號量操作以後,可以呼叫sem_close函式來釋放任何訊號量的資源。函式說明如下:

#include 

int sem_close(sem_t *sem);

link with -pthread.返回值:若成功,返回 0 ;若出錯,返回-1

複製**

如果程序沒有呼叫該函式便退出了,核心會自動關閉任何開啟的訊號量。無論是呼叫該函式還是核心自動關閉,都不會改變釋放之前的訊號量值。

銷毀可以使用sem_unlink函式銷毀乙個有名訊號量。函式說明如下:

#include 

int sem_unlink(const char *name);

link with -pthread.返回值:若成功,返回 0 ;若出錯,返回-1

複製**

sem_unlink函式會刪除訊號量的名字。如果沒有開啟的訊號量引用,則該訊號量會被銷毀,否則,銷毀會推遲到最後乙個開啟的引用關閉時才進行。

例子例如,管道通訊中,如果父程序使用fork()建立兩個子程序1和2,子程序1,2按順序向管道寫一段文字,最後父程序從管道將子程序寫入的內容讀出來,要保證程序執行的先後順序,可以用有名訊號量來解決。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

intmain

()else

if(pid1==0)elseelse

if(pid2==0)

if(pid1 > 0 && pid2 >0)

sem_unlink("name_sem1");

sem_unlink("name_sem2");

}return0;}

複製**

建立

無名訊號量可以通過sem_init函式建立,函式說明如下:

#include 

int sem_init(sem_t *sem, int pshared, unsigned int value);

link with -pthread.返回值:若成功,返回 0 ;若出錯,返回-1

複製**

pshared 引數指示該訊號量是被乙個程序的多個執行緒共享還是被多個程序共享。

如果 pshared 的值為 0 ,那麼訊號量將被單程序中的多執行緒共享,並且應該位於某個位址,該位址對所有執行緒均可見(例如,全域性變數或變數在堆上動態分配)。

如果 pshared 非零,那麼訊號量將在程序之間共享,並且訊號量應該位於共享記憶體區域。

銷毀如果無名訊號量使用完成,可以呼叫sem_destory函式銷毀該訊號量。函式說明如下:

#include 

int sem_destroy(sem_t *sem);

link with -pthread.返回值:若成功,返回 0 ;若出錯,返回-1

複製**

注意:

例子

使用無名訊號量實現有名訊號量中的例子:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

intmain

() shm = shmat(shmid, 0, 0);//返回指向共享記憶體第乙個位元組的指標

shared = (sem_t *)shm;

sem_init(shared, 1, 0);//初始化共享記憶體訊號量值為0

pipe(fd);//建立乙個無名管道

pid1 = fork();

if(pid1<0)else

if(pid1==0)elseelse

if(pid2==0)

if(pid1 > 0 && pid2 >0)

}return0;}

複製**

程序間通訊 POSIX 有名訊號量與無名訊號量

在 posix 系統中,程序間通訊是乙個很有意思的話題。posix訊號量程序是3種 ipc inter process communication 機制之一,3種 ipc 機制源於 posix.1 的實時擴充套件。single unix specification 將3種機制 訊息佇列,訊號量和共享...

程序間通訊之Posix 訊號量

概述 訊號量 semaphore 是一種用於提供不同程序間或者乙個給定程序的不同執行緒間同步手段的原語。1.posix 有名訊號量 使用posix ipc 名字標識,可用於程序或執行緒間的同步。2.posix 基於記憶體的訊號量 存放在共享記憶體區中,可用於程序或執行緒間的同步。我們暫時只考慮不同程...

程序間通訊 訊號量

ipc識別符號和關鍵字 在終端輸入ipcs,可以看到目前系統中所有的ipc資訊 第一列的key就是ipc的關鍵字,第二列是ipc的識別符號。ftok 函式用於獲得乙個ipc的關鍵字,其函式原型是 key t ftok const char pathname,int proj id 下面是乙個訊號量的...