semget() semop()

semget()


     可使用系統調用semget()建立一個新的信號量集,或者存取一個已經存在的信號量集:linux

系統調用:semget();
原型:intsemget(key_t key,int nsems,int semflg);
返回值:若是成功,則返回信號量集的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指出了一個新的信號量集中應該建立的信號量的個數。信號量集中最多的信號量的個數是 在linux/sem.h中定義的:
#defineSEMMSL32/*<=512maxnumofsemaphoresperid*/
下面是一個打開和建立信號量集的程序:
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

功能描述

操做一個或一組信號。

用法

#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);

參數

semid:信號集的識別碼,可經過semget獲取。
sops:指向存儲信號操做結構的數組指針,信號操做結構的原型以下
struct sembuf
{
unsigned short sem_num; /* semaphore number */
short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
};
這三個字段的意義分別爲:
sem_num:操做信號在信號集中的編號,第一個信號的編號是0。
sem_op:若是其值爲正數,該值會加到現有的信號內含值中。一般用於釋放所控資源的使用權;若是sem_op的 值爲負數,而其絕對值又大於信號的現值,操做將會阻塞,直到信號值大於或等於sem_op的絕對值。一般用於獲取資源的使用權;若是sem_op的值爲 0,則操做將暫時阻塞,直到信號的值變爲0。
sem_flg:信號操做標誌,可能的選擇有兩種
IPC_NOWAIT //對信號的操做不能知足時,semop()不會阻塞,並當即返回,同時設定 錯誤信息
SEM_UNDO //程序結束時(不論正常或不正常),保證信號值會被重設爲semop()調用前的值。這樣作的目的在於避免程序在異常狀況下結束時未將鎖定的資源解鎖,形成該資源永遠鎖定。
nsops:信號操做結構的數量,恆大於或等於1。
timeout:當semtimedop()調用導致進程進入睡眠時,睡眠時間不能超過本參數指定的值。若是睡眠超時,semtimedop()將失敗返回,並設定 錯誤值爲EAGAIN。若是本參數的值爲NULL,semtimedop()將永遠睡眠等待。

返回說明

成功執行時,兩個 系統調用都返回0。失敗返回-1,errno被設爲如下的某個值
E2BIG:一次對信號的 操做數超出系統的限制
EACCES:調用進程沒有權能執行請求的操做,而且不具備CAP_IPC_OWNER權能
EAGAIN:信號操做暫時不能知足,須要重試
EFAULT:sops或timeout 指針指向的空間不可訪問
EFBIG:sem_num指定的值無效
EIDRM:信號集已被移除
EINTR:系統調用阻塞時,被信號中斷
EINVAL:參數無效
ENOMEM: 內存不足
ERANGE:信號所容許的值越界
 
============================================================================
 
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; }
相關文章
相關標籤/搜索