信号量函数 semget() semop() semctl()
生活随笔
收集整理的這篇文章主要介紹了
信号量函数 semget() semop() semctl()
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
semget()
???? 可以使用系統(tǒng)調(diào)用semget() 創(chuàng)建一個新的信號量集,或者存取一個已經(jīng)存在的信號量集 : 系統(tǒng)調(diào)用:semget();
原型:intsemget(key_t key,int nsems,int semflg);
返回值:如果成功,則返回信號量集的IPC標識符。如果失敗,則返回-1:errno=EACCESS(沒有權限)
EEXIST(信號量集已經(jīng)存在,無法創(chuàng)建)
EIDRM(信號量集已經(jīng)刪除)
ENOENT(信號量集不存在,同時沒有使用IPC_CREAT)
ENOMEM(沒有足夠的內(nèi)存創(chuàng)建新的信號量集)
ENOSPC(超出限制) ??? 系統(tǒng)調(diào)用semget()的第一個參數(shù)是關鍵字值(一般是由系統(tǒng)調(diào)用ftok()返回的)。系統(tǒng)內(nèi)核將此值和系統(tǒng)中存在的其他的信號量集的關鍵字值進行比較。打開和存取操作與參數(shù)semflg中的內(nèi)容相關。IPC_CREAT如果信號量集在系統(tǒng)內(nèi)核中不存在,則創(chuàng)建信號量集。IPC_EXCL當和 IPC_CREAT一同使用時,如果信號量集已經(jīng)存在,則調(diào)用失敗。如果單獨使用IPC_CREAT,則semget()要么返回新創(chuàng)建的信號量集的標識符,要么返回系統(tǒng)中已經(jīng)存在的同樣的關鍵字值的信號量的標識符。如果IPC_EXCL和IPC_CREAT一同使用,則要么返回新創(chuàng)建的信號量集的標識符,要么返回-1。IPC_EXCL單獨使用沒有意義。參數(shù)nsems指出了一個新的信號量集中應該創(chuàng)建的信號量的個數(shù)。信號量集中最多的信號量的個數(shù)是在linux/sem.h中定義的: #defineSEMMSL32/*<=512maxnumofsemaphoresperid*/
下面是一個打開和創(chuàng)建信號量集的程序:
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()
系統(tǒng)調(diào)用:semop();
調(diào)用原型:int semop(int semid,struct sembuf*sops,unsign ednsops);
返回值:0,如果成功。-1,如果失敗:errno=E2BIG(nsops大于最大的ops數(shù)目)
EACCESS(權限不夠)
EAGAIN(使用了IPC_NOWAIT,但操作不能繼續(xù)進行)
EFAULT(sops指向的地址無效)
EIDRM(信號量集已經(jīng)刪除)
EINTR(當睡眠時接收到其他信號)
EINVAL(信號量集不存在,或者semid無效)
ENOMEM(使用了SEM_UNDO,但無足夠的內(nèi)存創(chuàng)建所需的數(shù)據(jù)結(jié)構(gòu))
ERANGE(信號量值超出范圍) 第一個參數(shù)是關鍵字值。第二個參數(shù)是指向?qū)⒁僮鞯臄?shù)組的指針。第三個參數(shù)是數(shù)組中的操作的個數(shù)。參數(shù)sops指向由sembuf組成的數(shù)組。此數(shù)組是在linux/sem.h中定義的: /*semop systemcall takes an array of these*/
structsembuf{
ushortsem_num;/*semaphore index in array*/
shortsem_op;/*semaphore operation*/
shortsem_flg;/*operation flags*/
sem_num將要處理的信號量的個數(shù)。
sem_op要執(zhí)行的操作。
sem_flg操作標志。 如果sem_op是負數(shù),那么信號量將減去它的值。這和信號量控制的資源有關。如果沒有使用IPC_NOWAIT,那么調(diào)用進程將進入睡眠狀態(tài),直到信號量控制的資源可以使用為止。如果sem_op是正數(shù),則信號量加上它的值。這也就是進程釋放信號量控制的資源。最后,如果sem_op是0,那么調(diào)用進程將調(diào)用sleep(),直到信號量的值為0。這在一個進程等待完全空閑的資源時使用。 =============================================================== semctl()
系統(tǒng)調(diào)用:semctl();
原型:int semctl(int semid,int semnum,int cmd,union semunarg);
返回值:如果成功,則為一個正數(shù)。
如果失敗,則為-1:errno=EACCESS(權限不夠)
EFAULT(arg指向的地址無效)
EIDRM(信號量集已經(jīng)刪除)
EINVAL(信號量集不存在,或者semid無效)
EPERM(EUID沒有cmd的權利)
ERANGE(信號量值超出范圍) 系統(tǒng)調(diào)用semctl用來執(zhí)行在信號量集上的控制操作。這和在消息隊列中的系統(tǒng)調(diào)用msgctl是十分相似的。但這兩個系統(tǒng)調(diào)用的參數(shù)略有不同。因為信號量一般是作為一個信號量集使用的,而不是一個單獨的信號量。所以在信號量集的操作中,不但要知道IPC關鍵字值,也要知道信號量集中的具體的信號量。這兩個系統(tǒng)調(diào)用都使用了參數(shù)cmd,它用來指出要操作的具體命令。兩個系統(tǒng)調(diào)用中的最后一個參數(shù)也不一樣。在系統(tǒng)調(diào)用msgctl中,最后一個參數(shù)是指向內(nèi)核中使用的數(shù)據(jù)結(jié)構(gòu)的指針。我們使用此數(shù)據(jù)結(jié)構(gòu)來取得有關消息隊列的一些信息,以及設置或者改變隊列的存取權限和使用者。但在信號量中支持額外的可選的命令,這樣就要求有一個更為復雜的數(shù)據(jù)結(jié)構(gòu)。
系統(tǒng)調(diào)用semctl()的第一個參數(shù)是關鍵字值。第二個參數(shù)是信號量數(shù)目。 參數(shù)cmd中可以使用的命令如下:
??? ·IPC_STAT讀取一個信號量集的數(shù)據(jù)結(jié)構(gòu)semid_ds,并將其存儲在semun中的buf參數(shù)中。
??? ·IPC_SET設置信號量集的數(shù)據(jù)結(jié)構(gòu)semid_ds中的元素ipc_perm,其值取自semun中的buf參數(shù)。
??? ·IPC_RMID將信號量集從內(nèi)存中刪除。
??? ·GETALL用于讀取信號量集中的所有信號量的值。
??? ·GETNCNT返回正在等待資源的進程數(shù)目。
??? ·GETPID返回最后一個執(zhí)行semop操作的進程的PID。
??? ·GETVAL返回信號量集中的一個單個的信號量的值。
??? ·GETZCNT返回這在等待完全空閑的資源的進程數(shù)目。
??? ·SETALL設置信號量集中的所有的信號量的值。
??? ·SETVAL設置信號量集中的一個單獨的信號量的值。 參數(shù)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當執(zhí)行SETVAL命令時使用。buf在IPC_STAT/IPC_SET命令中使用。代表了內(nèi)核中使用的信號量的數(shù)據(jù)結(jié)構(gòu)。array在使用GETALL/SETALL命令時使用的指針。
??? 下面的程序返回信號量的值。當使用GETVAL命令時,調(diào)用中的最后一個參數(shù)被忽略: 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);
} 注意系統(tǒng)調(diào)用semctl中的最后一個參數(shù)是一個聯(lián)合類型的副本,而不是一個指向聯(lián)合類型的指針。
#include?
#include?
#include?
#include?
#include?
#include?
#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;
}
???? 可以使用系統(tǒng)調(diào)用semget() 創(chuàng)建一個新的信號量集,或者存取一個已經(jīng)存在的信號量集 : 系統(tǒng)調(diào)用:semget();
原型:intsemget(key_t key,int nsems,int semflg);
返回值:如果成功,則返回信號量集的IPC標識符。如果失敗,則返回-1:errno=EACCESS(沒有權限)
EEXIST(信號量集已經(jīng)存在,無法創(chuàng)建)
EIDRM(信號量集已經(jīng)刪除)
ENOENT(信號量集不存在,同時沒有使用IPC_CREAT)
ENOMEM(沒有足夠的內(nèi)存創(chuàng)建新的信號量集)
ENOSPC(超出限制) ??? 系統(tǒng)調(diào)用semget()的第一個參數(shù)是關鍵字值(一般是由系統(tǒng)調(diào)用ftok()返回的)。系統(tǒng)內(nèi)核將此值和系統(tǒng)中存在的其他的信號量集的關鍵字值進行比較。打開和存取操作與參數(shù)semflg中的內(nèi)容相關。IPC_CREAT如果信號量集在系統(tǒng)內(nèi)核中不存在,則創(chuàng)建信號量集。IPC_EXCL當和 IPC_CREAT一同使用時,如果信號量集已經(jīng)存在,則調(diào)用失敗。如果單獨使用IPC_CREAT,則semget()要么返回新創(chuàng)建的信號量集的標識符,要么返回系統(tǒng)中已經(jīng)存在的同樣的關鍵字值的信號量的標識符。如果IPC_EXCL和IPC_CREAT一同使用,則要么返回新創(chuàng)建的信號量集的標識符,要么返回-1。IPC_EXCL單獨使用沒有意義。參數(shù)nsems指出了一個新的信號量集中應該創(chuàng)建的信號量的個數(shù)。信號量集中最多的信號量的個數(shù)是在linux/sem.h中定義的: #defineSEMMSL32/*<=512maxnumofsemaphoresperid*/
下面是一個打開和創(chuàng)建信號量集的程序:
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()
系統(tǒng)調(diào)用:semop();
調(diào)用原型:int semop(int semid,struct sembuf*sops,unsign ednsops);
返回值:0,如果成功。-1,如果失敗:errno=E2BIG(nsops大于最大的ops數(shù)目)
EACCESS(權限不夠)
EAGAIN(使用了IPC_NOWAIT,但操作不能繼續(xù)進行)
EFAULT(sops指向的地址無效)
EIDRM(信號量集已經(jīng)刪除)
EINTR(當睡眠時接收到其他信號)
EINVAL(信號量集不存在,或者semid無效)
ENOMEM(使用了SEM_UNDO,但無足夠的內(nèi)存創(chuàng)建所需的數(shù)據(jù)結(jié)構(gòu))
ERANGE(信號量值超出范圍) 第一個參數(shù)是關鍵字值。第二個參數(shù)是指向?qū)⒁僮鞯臄?shù)組的指針。第三個參數(shù)是數(shù)組中的操作的個數(shù)。參數(shù)sops指向由sembuf組成的數(shù)組。此數(shù)組是在linux/sem.h中定義的: /*semop systemcall takes an array of these*/
structsembuf{
ushortsem_num;/*semaphore index in array*/
shortsem_op;/*semaphore operation*/
shortsem_flg;/*operation flags*/
sem_num將要處理的信號量的個數(shù)。
sem_op要執(zhí)行的操作。
sem_flg操作標志。 如果sem_op是負數(shù),那么信號量將減去它的值。這和信號量控制的資源有關。如果沒有使用IPC_NOWAIT,那么調(diào)用進程將進入睡眠狀態(tài),直到信號量控制的資源可以使用為止。如果sem_op是正數(shù),則信號量加上它的值。這也就是進程釋放信號量控制的資源。最后,如果sem_op是0,那么調(diào)用進程將調(diào)用sleep(),直到信號量的值為0。這在一個進程等待完全空閑的資源時使用。 =============================================================== semctl()
系統(tǒng)調(diào)用:semctl();
原型:int semctl(int semid,int semnum,int cmd,union semunarg);
返回值:如果成功,則為一個正數(shù)。
如果失敗,則為-1:errno=EACCESS(權限不夠)
EFAULT(arg指向的地址無效)
EIDRM(信號量集已經(jīng)刪除)
EINVAL(信號量集不存在,或者semid無效)
EPERM(EUID沒有cmd的權利)
ERANGE(信號量值超出范圍) 系統(tǒng)調(diào)用semctl用來執(zhí)行在信號量集上的控制操作。這和在消息隊列中的系統(tǒng)調(diào)用msgctl是十分相似的。但這兩個系統(tǒng)調(diào)用的參數(shù)略有不同。因為信號量一般是作為一個信號量集使用的,而不是一個單獨的信號量。所以在信號量集的操作中,不但要知道IPC關鍵字值,也要知道信號量集中的具體的信號量。這兩個系統(tǒng)調(diào)用都使用了參數(shù)cmd,它用來指出要操作的具體命令。兩個系統(tǒng)調(diào)用中的最后一個參數(shù)也不一樣。在系統(tǒng)調(diào)用msgctl中,最后一個參數(shù)是指向內(nèi)核中使用的數(shù)據(jù)結(jié)構(gòu)的指針。我們使用此數(shù)據(jù)結(jié)構(gòu)來取得有關消息隊列的一些信息,以及設置或者改變隊列的存取權限和使用者。但在信號量中支持額外的可選的命令,這樣就要求有一個更為復雜的數(shù)據(jù)結(jié)構(gòu)。
系統(tǒng)調(diào)用semctl()的第一個參數(shù)是關鍵字值。第二個參數(shù)是信號量數(shù)目。 參數(shù)cmd中可以使用的命令如下:
??? ·IPC_STAT讀取一個信號量集的數(shù)據(jù)結(jié)構(gòu)semid_ds,并將其存儲在semun中的buf參數(shù)中。
??? ·IPC_SET設置信號量集的數(shù)據(jù)結(jié)構(gòu)semid_ds中的元素ipc_perm,其值取自semun中的buf參數(shù)。
??? ·IPC_RMID將信號量集從內(nèi)存中刪除。
??? ·GETALL用于讀取信號量集中的所有信號量的值。
??? ·GETNCNT返回正在等待資源的進程數(shù)目。
??? ·GETPID返回最后一個執(zhí)行semop操作的進程的PID。
??? ·GETVAL返回信號量集中的一個單個的信號量的值。
??? ·GETZCNT返回這在等待完全空閑的資源的進程數(shù)目。
??? ·SETALL設置信號量集中的所有的信號量的值。
??? ·SETVAL設置信號量集中的一個單獨的信號量的值。 參數(shù)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當執(zhí)行SETVAL命令時使用。buf在IPC_STAT/IPC_SET命令中使用。代表了內(nèi)核中使用的信號量的數(shù)據(jù)結(jié)構(gòu)。array在使用GETALL/SETALL命令時使用的指針。
??? 下面的程序返回信號量的值。當使用GETVAL命令時,調(diào)用中的最后一個參數(shù)被忽略: 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);
} 注意系統(tǒng)調(diào)用semctl中的最后一個參數(shù)是一個聯(lián)合類型的副本,而不是一個指向聯(lián)合類型的指針。
#include?
#include?
#include?
#include?
#include?
#include?
#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;
}
總結(jié)
以上是生活随笔為你收集整理的信号量函数 semget() semop() semctl()的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 无锁编程[0]__多线程条件下的计数器_
- 下一篇: Linux环境进程间通信 信号量