訊號量函式 semget() semop() semctl()

helloxchen發表於2010-11-26
semget()

可以使用系統呼叫semget()建立一個新的訊號量集,或者存取一個已經存在的訊號量集:
系統呼叫: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()

系統呼叫: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(訊號量值超出範圍)
第一個引數是關鍵字值。第二個引數是指向將要操作的陣列的指標。第三個引數是陣列中的操作的個數。引數sops指向由sembuf組成的陣列。此陣列是在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將要處理的訊號量的個數。
sem_op要執行的操作。
sem_flg操作標誌。
如果sem_op是負數,那麼訊號量將減去它的值。這和訊號量控制的資源有關。如果沒有使用IPC_NOWAIT,那麼呼叫程式將進入睡眠狀態,直到訊號量控制的資源可以使用為止。如果sem_op是正數,則訊號量加上它的值。這也就是程式釋放訊號量控制的資源。最後,如果sem_op是0,那麼呼叫程式將呼叫sleep(),直到訊號量的值為0。這在一個程式等待完全空閒的資源時使用。
===============================================================
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;xprintf("Printer%d:%dnr",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
#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 errorn");
}
argument.val=inival;
if (semctl(id,0,SETVAL,argument)<0)
{
printf("semctrl errorn");
}
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 %dn",i);
return i++;
}

void consumeItem(int item)
{
printf("Consume a product %dn",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;
}http://blog.chinaunix.net/u3/103892/showart_2113644.html
[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24790158/viewspace-1042140/,如需轉載,請註明出處,否則將追究法律責任。

相關文章