訊號量的操作——semop函數
(2011-08-03 18:25:05)
轉載▼
訊號量的值與相應資源的使用方式有關,當它的值大於 0 時,表示當前可用的資源數的數量;當它的值小於 0 時,其絕對值表示等待使用該資源的進程個數。訊號量的值僅能由 PV 操作來改變。
在 Linux 下,PV 操作通過調用semop函數來實現。該函數定義在標頭檔 sys/sem.h中,原型如下: int semop(int semid,struct sembuf *sops,size_t nsops); 函數的參數 semid 為訊號量集的標識符;參數 sops 指向進行操作的結構體數組的首地址;參數 nsops 指出將要進行操作的訊號的個數。semop 函數調用成功返回 0,失敗返回 -1。 semop 的第二個參數 sops 指向的結構體數組中,每個 sembuf 結構體對應一個特定訊號的操作。因此對訊號量進行操作必須熟悉該資料結構,該結構定義在 linux/sem.h,如下所示: struct sembuf{ unsigned short sem_num; //訊號在訊號集中的索引,0代表第一個訊號,1代表第二個訊號 short sem_op; //操作類型 short sem_flg; //操作標誌 }; 下面詳細介紹一下 sembuf 的幾個參數:--------------------------------------------------------------------------------------------------
sem_op > 0 訊號加上 sem_op 的值,表示進程釋放控制的資源; sem_op = 0 如果沒有設定 IPC_NOWAIT,則調用進程進入睡眠狀態,直到訊號
量的值為0;否則進程不回睡眠,直接返回 EAGAIN sem_op < 0 訊號加上 sem_op 的值。若沒有設定 IPC_NOWAIT ,則調用進程阻 塞,直到資源可用;否則進程直接返回EAGAIN
該參數可設定為 IPC_NOWAIT 或 SEM_UNDO 兩種狀態。只有將 sem_flg 指定為 SEM_UNDO 標誌後,semadj (所指定訊號量針對調用進程的調整值)才會更新。
此外,如果此操作指定SEM_UNDO,系統更新過程中會撤消此號誌的計數(semadj)。此操作可以隨時進行---它永遠不會強制等待的過程。調用進程必須有改變訊號量集的許可權。 sem_flg公認的標誌是 IPC_NOWAIT 和 SEM_UNDO。如果操作指定SEM_UNDO,它將會自動撤消該進程終止時。
在標準操作程式中的操作是在數組的順序執行、原子的,那就是,該操作要麼作為一個完整的單元,要麼不。如果不是所有操作都可以立即執行的系統調用的行為取決於在個人sem_flg領域的IPC_NOWAIT標誌的存在。
-------------------------------------------------------------------------------------------------
對訊號量最基本的操作就是進行PV操作,而System V訊號量正是通過 semop 函數和 sembuf 結構體的資料結構來進行PV操作的。
當 sembuf 的第二個資料結構 sem_op 設定為負數時,是對它進行P操作,即減1操作;當設定為正數時,就是進行V操作,即加1操作。 下面舉一個對一個訊號量集中的某個訊號進行 PV 操作的函數實現: //P操作函數 int sem_p( int semid, int index ) { struct sembuf buf = { 0, -1, IPC_NOWAIT}; if ( index < 0 ) { perror ( "index of array cannot equals a minus value!\n" ); return -1; } buf.sem_num = index; if ( semop ( semid, &buf, 1) == -1) { perroe ( " a wrong operation to semaphore occurred!\n" ); return -1; } return 0; } //V操作函數 int sem_p( int semid, int index )
{ struct sembuf buf = { 0, 1, IPC_NOWAIT}; if ( index < 0 ) { perror ( "index of array cannot equals a minus value!\n" ); return -1; } buf.sem_num = index; if ( semop ( semid, &buf, 1) == -1) { perroe ( " a wrong operation to semaphore occurred!\n" ); return -1; } return 0; }