信號量函數 semget() semop() semctl()
Posted on 2009-03-05 15:30 Prayer 閱讀(2794) 評論(0) 編輯 收藏 引用 所屬分類: LINUX/UNIX/AIX問共享資源進行控制的機制,其實為了解決互斥共享資源的同步問題而引入的機制。
不能單獨定義一個信號量,而只能定義一個信號量集,其中包括一組信號量,同意信號量集中的信號量使用同
一引用ID,這樣設置是為了多個資源或同步操作的需要。
與信號量有關的幾個系統調用函數:
1、信號量集得創建與打開 semget()
原型:int semget(key_t key,int nsems,int semflg);
其中 參數key表示所創建或打開信號量集的鍵。
參數nsems表示創建的信號量集中的信號量的個數,該參數只在創建信號量集時有效。
參數flag表示調用函數的操作類型,也可用于設置信號量集的訪問權限,兩者通過or表示。
當調用semget創建一個信號量時,他的相應的semid_ds結構被初始化。ipc_perm中各個量被設置為相應
值,sem_nsems被設置為nsems所示的值,sem_otime被設置為0,sem_ctime被設置為當前時間
返回值:如果成功,則返回信號量集的IPC標識符。如果失敗,則返回-1:errno=EACCESS(沒有權限)
EEXIST(信號量集已經存在,無法創建)
EIDRM(信號量集已經刪除)
ENOENT(信號量集不存在,同時沒有使用IPC_CREAT)
ENOMEM(沒有足夠的內存創建新的信號量集)
ENOSPC(超出限制)
系統調用semget()的第一個參數是關鍵字值(一般是由系統調用ftok()返回的)。系統內核將此值和系統中
存在的其他的信號量集的關鍵字值進行比
較。打開和存取操作與參數semflg中的內容相關。IPC_CREAT如果
信號量集在系統內核中不存在,則創建信號量集。IPC_EXCL當和
IPC_CREAT一同使用時,如果信號量集已經
存在,則調用失敗。如果單獨使用IPC_CREAT,則semget()要么返回新創建的信號量集的標識
符,要么返回
系統中已經存在的同樣的關鍵字值的信號量的標識符。如果IPC_EXCL和IPC_CREAT一同使用,則要么返回新
創建的信號量集的標識
符,要么返回-1。IPC_EXCL單獨使用沒有意義。參數nsems指出了一個新的信號量集
中應該創建的信號量的個數。
2、信號量的操作 semop()
調用原型:int semop(int semid,struct sembuf*sops,unsign ednsops);
其中 semid為信號量集引用ID。
semoparray是一個sembuff結構數組,sembuff結構用于指定調用semop函數所作的操作,數組
semoparray元素的個數有參數nops指出。
semoparray是一個數組,其中每個元素表是一個操作,由于此函數是一個原子操作,一旦執行就
將執行數組中的所有操作。
返回值:0,如果成功。-1,如果失敗:errno=E2BIG(nsops大于最大的ops數目)
EACCESS(權限不夠)
EAGAIN(使用了IPC_NOWAIT,但操作不能繼續進行)
EFAULT(sops指向的地址無效)
EIDRM(信號量集已經刪除)
EINTR(當睡眠時接收到其他信號)
EINVAL(信號量集不存在,或者semid無效)
ENOMEM(使用了SEM_UNDO,但無足夠的內存創建所需的數據結構)
ERANGE(信號量值超出范圍)
如果sem_op是負數,那么信號量將減去它的值。這和信號量控制的資源有關。如果沒有使用IPC_NOWAIT,
那么調用進程將進入睡眠狀態,直到信號
量控制的資源可以使用為止。如果sem_op是正數,則信號量加上
它的值。這也就是進程釋放信號量控制的資源。最后,如果sem_op是0,那么調用進程
將調用sleep(),
直到信號量的值為0。這在一個進程等待完全空閑的資源時使用。
3、信號量的控制 semctl()
原型:int semctl(int semid,int semnum,int cmd,union semun arg);
其中 semid為信號量集引用標志符。
semnum用于指定某個特定信號量。
cmd表示調用該函數執行的操作,其取值和對應操作如下:
.IPC_STAT讀取一個信號量集的數據結構semid_ds,并將其存儲在semun中的buf參數中。
·IPC_SET設置信號量集的數據結構semid_ds中的元素ipc_perm,其值取自semun中的buf參數。
·IPC_RMID將信號量集從內存中刪除。
·GETALL用于讀取信號量集中的所有信號量的值。
·GETNCNT返回正在等待資源的進程數目。
·GETPID返回最后一個執行semop操作的進程的PID。
·GETVAL返回信號量集中的一個單個的信號量的值。
·GETZCNT返回這在等待完全空閑的資源的進程數目。
·SETALL設置信號量集中的所有的信號量的值。
·SETVAL設置信號量集中的一個單獨的信號量的值。
arg是semnu的是一個聯合類型的副本,而不是一個指向聯合類型的指針。聯合中各個量的使用情況
和參數cmd的設置有關。
參考文獻:linux環境下C編程指南
http://qq164587043.blog.51cto.com/261469/51549
可以使用系統調用semget()創建一個新的信號量集,或者存取一個已經存在的信號量集:
原型:intsemget(key_t key,int nsems,int semflg);
返回值:如果成功,則返回信號量集的IPC標識符。如果失敗,則返回-1:errno=EACCESS(沒有權限)
EEXIST(信號量集已經存在,無法創建)
EIDRM(信號量集已經刪除)
ENOENT(信號量集不存在,同時沒有使用IPC_CREAT)
ENOMEM(沒有足夠的內存創建新的信號量集)
ENOSPC(超出限制)
下面是一個打開和創建信號量集的程序:
intopen_semaphore_set(key_t keyval,int numsems)
{
intsid;
if(!numsems)
return(-1);
if((sid=semget(mykey,numsems,IPC_CREAT|0660))==-1)
{
return(-1);
}
return(sid);
}
};
系統調用:semop();
調用原型:int semop(int semid,struct sembuf*sops,unsign ednsops);
返回值:0,如果成功。-1,如果失敗:errno=E2BIG(nsops大于最大的ops數目)
EACCESS(權限不夠)
EAGAIN(使用了IPC_NOWAIT,但操作不能繼續進行)
EFAULT(sops指向的地址無效)
EIDRM(信號量集已經刪除)
EINTR(當睡眠時接收到其他信號)
EINVAL(信號量集不存在,或者semid無效)
ENOMEM(使用了SEM_UNDO,但無足夠的內存創建所需的數據結構)
ERANGE(信號量值超出范圍)
structsembuf{
ushortsem_num;/*semaphore index in array*/
shortsem_op;/*semaphore operation*/
shortsem_flg;/*operation flags*/
sem_num將要處理的信號量的個數。
sem_op要執行的操作。
sem_flg操作標志。
系統調用:semctl();
原型:int semctl(int semid,int semnum,int cmd,union semunarg);
返回值:如果成功,則為一個正數。
如果失敗,則為-1:errno=EACCESS(權限不夠)
EFAULT(arg指向的地址無效)
EIDRM(信號量集已經刪除)
EINVAL(信號量集不存在,或者semid無效)
EPERM(EUID沒有cmd的權利)
ERANGE(信號量值超出范圍)
系統調用semctl()的第一個參數是關鍵字值。第二個參數是信號量數目。
·IPC_STAT讀取一個信號量集的數據結構semid_ds,并將其存儲在semun中的buf參數中。
·IPC_SET設置信號量集的數據結構semid_ds中的元素ipc_perm,其值取自semun中的buf參數。
·IPC_RMID將信號量集從內存中刪除。
·GETALL用于讀取信號量集中的所有信號量的值。
·GETNCNT返回正在等待資源的進程數目。
·GETPID返回最后一個執行semop操作的進程的PID。
·GETVAL返回信號量集中的一個單個的信號量的值。
·GETZCNT返回這在等待完全空閑的資源的進程數目。
·SETALL設置信號量集中的所有的信號量的值。
·SETVAL設置信號量集中的一個單獨的信號量的值。
/*arg for semctl systemcalls.*/
unionsemun{
intval;/*value for SETVAL*/
structsemid_ds*buf;/*buffer for IPC_STAT&IPC_SET*/
ushort*array;/*array for GETALL&SETALL*/
structseminfo*__buf;/*buffer for IPC_INFO*/
void*__pad;
下面的程序返回信號量的值。當使用GETVAL命令時,調用中的最后一個參數被忽略:
{
return(semctl(sid,semnum,GETVAL,0));
}
printer_usage()
{
int x;
for(x=0;x<MAX_PRINTERS;x++)
printf("Printer%d:%d\n\r",x,get_sem_val(sid,x));
}
{
union semunsemopts;
semopts.val=initval;
semctl(sid,semnum,SETVAL,semopts);
}