semop() - Unix、Linux系統呼叫 - 技術教學
Tutorials Point


  Unix入門
  Unix Shell程式設計
  高階Unix
  Unix實用參考
  Unix實用資源
  精選閱讀

版權所有 © 2014 tutorialspoint



  首頁     參考資料     討論論壇     關於TP  

semop() - Unix、Linux系統呼叫


previous next AddThis Social Bookmark Button

廣告

名稱

semop, semtimedop - 訊號量操作

概要

 
#include <sys/types.h>
 
#include <sys/ipc.h>
 
#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, unsigned nsops);

int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout);

描述

訊號量集中每個訊號量都有以下關聯值

unsigned short  semval;   /* semaphore value */
unsigned short  semzcnt;  /* # waiting for zero */
unsigned short  semncnt;  /* # waiting for increase */
pid_t           sempid;   /* process that did last op */

semop() 對由 semid 指示的集合中選定的訊號量執行操作。由 sops 指向的陣列中的每個 nsops 元素都指定要對單個訊號量執行的操作。此結構的元素的型別為 struct sembuf,包含以下成員

unsigned short sem_num;  /* semaphore number */
short          sem_op;   /* semaphore operation */
short          sem_flg;  /* operation flags */

sem_flg 中識別的標誌為 IPC_NOWAITSEM_UNDO。如果操作指定 SEM_UNDO,則在程序終止時會自動撤消該操作。

包含在 sops 中的操作集是原子執行的,也就是說,這些操作同時執行,並且只有在它們都能同時執行的情況下才能執行。如果並非所有操作都能立即執行,則系統呼叫的行為取決於 IPC_NOWAIT 標誌在各個 sem_flg 欄位中的存在情況,如下所述。

每個操作都在訊號量集的第 sem_num 個訊號量上執行,其中集合的第一個訊號量的編號為 0。根據 sem_op 的值,有三種類型的操作。

如果 sem_op 是一個正整數,則該操作會將此值新增到訊號量值 (semval)。此外,如果為此操作指定了 SEM_UNDO,則系統會更新此訊號量的程序撤消計數 (semadj)。此操作始終可以繼續進行 — 它永遠不會強制程序等待。呼叫程序必須對訊號量集具有更改許可權。

如果 sem_op 為零,則該程序必須對訊號量集具有讀取許可權。這是一個“等待為零”操作:如果 semval 為零,則該操作可以立即繼續。否則,如果在 sem_flg 中指定了 IPC_NOWAIT,則 semop() 失敗,並將 errno 設定為 EAGAIN(並且不執行 sops 中的任何操作)。否則,semzcnt(直到此訊號量值變為零為止的等待程序計數)將遞增一,並且程序將休眠,直到發生以下情況之一:

標籤描述
o semval 變為 0,此時 semzcnt 的值將遞減。
o訊號量集被刪除:semop() 失敗,並將 errno 設定為 EIDRM
o呼叫程序捕獲訊號:semzcnt 的值將遞減,並且 semop() 失敗,並將 errno 設定為 EINTR
osemtimedop() 呼叫中指定的 timeout 時間限制過期:semop() 失敗,並將 errno 設定為 EAGAIN
如果 sem_op 小於零,則該程序必須對訊號量集具有更改許可權。如果 semval 大於或等於 sem_op 的絕對值,則該操作可以立即繼續:sem_op 的絕對值將從 semval 中減去,並且,如果為此操作指定了 SEM_UNDO,則系統會更新此訊號量的程序撤消計數 (semadj)。如果 sem_op 的絕對值大於 semval,並且在 sem_flg 中指定了 IPC_NOWAIT,則 semop() 失敗,並將 errno 設定為 EAGAIN(並且不執行 sops 中的任何操作)。否則,semncnt(等待此訊號量值增加的程序計數器)將遞增一,並且程序將休眠,直到發生以下情況之一:
o semval 變得大於或等於 sem_op 的絕對值,此時 semncnt 的值將遞減,sem_op 的絕對值將從 semval 中減去,並且,如果為此操作指定了 SEM_UNDO,則系統會更新此訊號量的程序撤消計數 (semadj)。
o訊號量集從系統中刪除:semop() 失敗,並將 errno 設定為 EIDRM
o呼叫程序捕獲訊號:semncnt 的值將遞減,並且 semop() 失敗,並將 errno 設定為 EINTR
osemtimedop() 呼叫中指定的 timeout 時間限制過期:系統呼叫失敗,並將 errno 設定為 EAGAIN
成功完成時,將為由 sops 指向的陣列中指定的每個訊號量設定 sempid 值,以指示呼叫程序的程序 ID。此外,sem_otime 將設定為當前時間。

semtimedop() 的行為與 semop() 完全相同,只是在呼叫程序將休眠的情況下,休眠的持續時間受由 timespec 結構指定的已用時間量限制,其地址已傳遞到 timeout 引數中。如果已達到指定的時間限制,則 semtimedop() 失敗,並將 errno 設定為 EAGAIN(並且不執行 sops 中的任何操作)。如果 timeout 引數為 NULL,則 semtimedop() 的行為與 semop() 完全相同。

返回值

如果成功,semop() 和 semtimedop() 返回 0;否則,它們返回 -1,其中 errno 指示錯誤。

錯誤

失敗時,errno 將設定為以下值之一:
標籤描述
E2BIG 引數 nsops 大於 SEMOPM(每次系統呼叫允許的最大運算元)。
EACCES 呼叫程序不具有執行指定的訊號量操作所需的許可權,並且不具有 CAP_IPC_OWNER 功能。
EAGAIN 操作無法立即繼續,並且在 sem_flg 中指定了 IPC_NOWAITtimeout 中指定的時間限制已過期。
EFAULT sopstimeout 引數中指定的地址不可訪問。
EFBIG 對於某些操作,sem_num 的值小於 0 或大於或等於集合中訊號量的數量。
EIDRM 訊號量集已被刪除。
EINTR 在此係統呼叫中阻塞時,程序捕獲了訊號。
EINVAL 訊號量集不存在,或者 semid 小於零,或者 nsops 的值為非正數。
ENOMEM 某些操作的 sem_flg 指定了 SEM_UNDO,並且系統沒有足夠的記憶體來分配撤消結構。
ERANGE 對於某些操作,sem_op+semval 大於 SEMVMXsemval 的實現相關的最大值)。

備註

程序的 sem_undo 結構不會在 fork(2) 系統呼叫中繼承,但會在 execve(2) 系統呼叫中繼承。

無論在建立訊號處理程式時 SA_RESTART 標誌的設定如何,semop() 都不會在被訊號處理程式中斷後自動重新啟動。

semadj 是一個每個程序的整數,它只是指定了 SEM_UNDO 標誌的所有訊號量操作的(負)計數。當使用 semctl(2) 對 SETVALSETALL 請求直接設定訊號量的值時,所有程序中相應的 semadj 值都將被清除。

可以使用適當的 semctl(2) 呼叫檢索訊號量的 semvalsempidsemzcntsemnct 值。

以下對訊號量集資源的限制會影響 semop() 呼叫:

標籤描述
SEMOPM 一次 semop() 呼叫允許的最大運算元 (32)(在 Linux 上,此限制可以透過 /proc/sys/kernel/sem 的第三個欄位讀取和修改)。
SEMVMX semval 的最大允許值:實現相關 (32767)。
該實現對退出最大調整值 (SEMAEM)、系統範圍內的最大撤消結構數 (SEMMNU) 和每個程序的最大撤消條目系統引數沒有固有限制。

semtimedop() 首次出現在 Linux 2.5.52 中,隨後被反向移植到核心 2.4.22 中。

錯誤

當程序終止時,其關聯的 semadj 結構集將用於撤消使用 SEM_UNDO 標誌執行的所有訊號量操作的效果。這會引發一個難題:如果這些訊號量調整中的一個(或多個)會導致嘗試將訊號量的值降低到零以下,則實現應該怎麼做?一種可能的方法是阻塞,直到所有訊號量調整都能執行。但這卻是不理想的,因為它可能會強制程序終止長時間阻塞。另一種可能性是完全忽略這些訊號量調整(有點類似於在為訊號量操作指定 IPC_NOWAIT 時失敗)。Linux 採用第三種方法:儘可能降低訊號量值(即降至零),並允許程序終止立即繼續。

在核心 2.6.x(x <= 10)中,存在一個錯誤,在某些情況下,它會阻止等待訊號量值變為零的程序在值實際變為零時被喚醒。此錯誤已在核心 2.6.11 中修復。

符合標準

SVr4、POSIX.1-2001。

參見



previous next Printer Friendly

廣告


  

廣告



廣告