int semtimedop(int semid, struct sembuf *sops, unsigned nsops, struct timespec *timeout);
sem_op:若是其值爲正數,該值會加到現有的信號內含值中。一般用於釋放所控資源的使用權;若是sem_op的 值爲負數,而其絕對值又大於信號的現值,操做將會阻塞,直到信號值大於或等於sem_op的絕對值。一般用於獲取資源的使用權;若是sem_op的值爲 0,則操做將暫時阻塞,直到信號的值變爲0。
SEM_UNDO //程序結束時(不論正常或不正常),保證信號值會被重設爲semop()調用前的值。這樣作的目的在於避免程序在異常狀況下結束時未將鎖定的資源解鎖,形成該資源永遠鎖定。
============================================================================
semctl()
系統調用:semctl();
原型:int semctl(int semid,int semnum,int cmd,union semunarg);
返回值:若是成功,則爲一個正數。
若是失敗,則爲-1:errno=EACCESS(權限不夠)
EFAULT(arg指向的地址無效)
EIDRM(信號量集已經刪除)
EINVAL(信號量集不存在,或者semid無效)
EPERM(EUID沒有cmd的權利)
ERANGE(信號量值超出範圍)
系統調用semctl用來執行在信號量集上的控制操做。這和在消息隊列中的系統調用msgctl是十分類似的。但這兩個系統調用的參數略有不一樣。由於信號 量通常是做爲一個信號量集使用的,而不是一個單獨的信號量。因此在信號量集的操做中,不但要知道IPC關鍵字值,也要知道信號量集中的具體的信號量。這兩 個系統調用都使用了參數cmd,它用來指出要操做的具體命令。兩個系統調用中的最後一個參數也不同。在系統調用msgctl中,最後一個參數是指向內核 中使用的數據結構的指針。咱們使用此數據結構來取得有關消息隊列的一些信息,以及設置或者改變隊列的存取權限和使用者。但在信號量中支持額外的可選的命 令,這樣就要求有一個更爲複雜的數據結構。
系統調用semctl()的第一個參數是關鍵字值。第二個參數是信號量數目。
參數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表明一個semun的實例。semun是在linux/sem.h中定義的:
/*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;
val當執行SETVAL命令時使用。buf在IPC_STAT/IPC_SET命令中使用。表明了內核中使用的信號量的數據結構。array在使用GETALL/SETALL命令時使用的指針。
下面的程序返回信號量的值。當使用GETVAL命令時,調用中的最後一個參數被忽略:
intget_sem_val(intsid,intsemnum)
{
return(semctl(sid,semnum,GETVAL,0));
}
下面是一個實際應用的例子:
#defineMAX_PRINTERS5
printer_usage()
{
int x;
for(x=0;x<MAX_PRINTERS;x++)
printf("Printer%d:%d\n\r",x,get_sem_val(sid,x));
}
下面的程序能夠用來初始化一個新的信號量值:
void init_semaphore(int sid,int semnum,int initval) { union semunsemopts; semopts.val=initval; semctl(sid,semnum,SETVAL,semopts); }
注意系統調用semctl中的最後一個參數是一個聯合類型的副本,而不是一個指向聯合類型的指針。 #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <stdio.h> #include <stdlib.h> #include <sys/shm.h> #define KEY1 1492 #define KEY2 1493 #define KEY3 1494 #define IFLAGS (IPC_CREAT|IPC_EXCL) #define N 1 #define SEMKEY1 (key_t)0x2000 #define SEMKEY2 (key_t)0x2001 #define SEMKEY3 (key_t)0x2002 union semun{ int val; struct semid_ds *buf; unsigned short * ary; }; int ctr_sem(key_t key,int inival) { union semun argument; int id; //if ((id=semget(key,1,IPC_CREAT))<0) if ((id=semget(key,1,IPC_CREAT))<0) { printf("semget error\n"); } argument.val=inival; if (semctl(id,0,SETVAL,argument)<0) { printf("semctrl error\n"); } return id; } int sem_init(key_t key, int inival) { int semid; union semun arg; semid=semget(key,1,0660|IFLAGS); arg.val=inival; semctl(semid, 0, SETVAL, arg); return semid; } void P(int semid) { struct sembuf sb; sb.sem_num=0; sb.sem_op=-1; sb.sem_flg=0; semop(semid,&sb,1); } void V(int semid) { struct sembuf sb; sb.sem_num=0; sb.sem_op=1; sb.sem_flg=0; semop(semid,&sb,1); } int productItem() { static int i=1; printf("Produce a product %d\n",i); return i++; } void consumeItem(int item) { printf("Consume a product %d\n",item); } int main(void) { int nshm=shmget(ftok("/root",'a'),1024,IPC_CREAT); int *buffer=(int *)shmat(nshm,0,0); // int products=ctr_sem(KEY1/*ftok("/home/jingenl",'p')*/,0); // int space=ctr_sem(KEY2/*ftok("/home/jingenl",'s')*/,N); // int mutex=ctr_sem(KEY3/*ftok("/home/jingenl",'m')*/,1); int products=sem_init(SEMKEY1,0); int space=sem_init(SEMKEY2,N); int mutex=sem_init(SEMKEY3,1); int i=0,j=0; if(fork()==0) { int item; while(1) { P(space); P(mutex); item=productItem(); *(buffer + sizeof(int)*i)=item; i=(i+1)%N; V(mutex); V(products); } } else { int item; while(1) { P(products); P(mutex); item=*(buffer + sizeof(int)*j); j=(j+1)%N; consumeItem(item); V(mutex); V(space); } } return 0; }