semget函式 semopt 採用訊號量處理多程序互斥同步
阿新 • • 發佈:2019-02-12
採用訊號量處理多程序互斥同步
訊號量與訊息類似,也是程序間通訊的一種方法。我們在這裡講的訊號量,實際上是一個包含訊號量元素陣列的訊號量集。訊號量元素與E.W.Dijkstra提出的整數訊號量相對應。在一個單系統呼叫中,程序可在完整的訊號量集上操作。
訊號量集的內部表示和各自訊號量元素不是直接可以訪問的,但每個訊號量元素必須包括下列各項:
l 一個標識訊號量元素的非負整數
l 最後操作訊號量元素的程序ID
l 等待訊號量元素值加1的程序數
l 等待訊號量元素值等於0的程序數
訊號量操作允許一個程序阻塞直到訊號量元素值為0或者直到它變為正數。每個元素具有兩個相關聯的佇列:一個是等待訊號量元素值加1的程序佇列,另一個是等待訊號量元素值等於0的程序佇列。
1、 semget函式
系統呼叫semget用來建立一個訊號量集並將每個元素初始化為0
#include<sys/ipc.h>
#include<sys/sem.h>
int semget(key_t key, int nsems, int semflg );
函式semget有3個引數。第1個引數為標識訊號量集的關鍵字,程式指定關鍵字的方法有三種:使用IPC_PRIVATE讓系統產生一個關鍵字、挑選一個隨機數,或者是使用ftok從檔案路徑名中產生一個關鍵字。第2個引數為訊號量集中的元素個數。第3個引數為訊號量存取權標誌與建立標誌,該引數的低9位是訊號量的存取權標誌;建立標誌有2個,IPC_CTEAT和IPC_EXCL。IPC_CREAT表示如果訊號量集不存在,則建立它; IPC_EXCL表示只有在訊號量集不存在的情況下,新的訊號量集才會被建立,否則semget返回-1,並設定errno。如果這兩個標誌聯合使用,則功能如同O_EXCL標誌於open。
函式semget呼叫成功時返回一個用於以後semctl等操作的整數控制代碼,失敗時返回-1。
在指定訊號量集的關鍵字時,我們可以使用ftok根據檔案路徑名產生一個關鍵字。
#include<sys/ipc.h>
key_t ftok(const char * pathname, int proj_id);
函式ftok的第1個引數為檔案路徑名,該檔案必須存在且程序對該檔案有訪問權。第2個引數為程式設計師指定的一個整數ID。該函式成功呼叫時返回一個關鍵字,如呼叫失敗,則返回-1。
2、 semctl函式
系統呼叫semctl可以對訊號量進行很多控制。
#include<sys/ipc.h>
#include<sem.h>
int semctl(int semid, int semnum, int cmd, /*union senum arg*/…);
函式的第1個引數為訊號量集的控制代碼。第2個引數指定訊號量集中的元素。第3個引數為執行的控制命令,常見的命令如下表:
命令名稱
表示的含義
GETVAL
獲得一個指定訊號量的值
GETPID
獲得操作此元素的最後程序的ID
GETNCNT
獲得等待元素增1的程序數
GETZCNT
獲得等待元素變為0的程序數
SETVAL
設定一個指定訊號量元素的值為arg.val
IPC_RMID
刪除一個訊號量
IPC_SET
設定訊號量的許可權
函式semctl在出現錯誤時返回-1並設定erro。當呼叫成功時,其返回值決定於引數cmd,當cmd為GETVAL、GETPID、GETNCNT或GETZCNT時,函式返回相應的值,當cmd為別的值時,返回0。
union senum定義可直接包含在程式中,因為系統的標頭檔案中並沒有定義它。它的定義如下:
union senum
{
int val;
struct semid_ds *buf;
ushort *array;
};
union senum中提到的semid_ds結構定義如下:
struct semid_ds
{
struct ipc_perm sem_perm; /*operation permission struct*/
time_t sem_otime; /*last semop() time*/
time_t sem_ctime; /*last time changed by semctl()*/
struct sem*sembase; /*ptr to first semaphore in array*/
struct sem_queue *sem_pending; /*pending operations*/
struct sem_queue *sem_pending_last; /*last pending operation*/
struct sem_undo *undo; /*undo requests on this array*/
unsigned short int sem_nsems; /*number of semaphores in set*/
};
3、 semop函式
系統呼叫semop可以對訊號量增1、減1或測試其是否為0。
#include <sys/ipc.h>
#include <sys/sem.h>
int sempo(int semid, struct sembuf *sops, unsigned int nsops);
函式semop的第1個引數為semget返回的控制代碼,第2個引數指向元素運算元組,第3個引數指定在陣列中元素操作的個數。
函式成功呼叫時返回0,失敗時返回-1。如果時被訊號中斷,則返回-1,同時設定errno為EINTR。
結構體sembuf的定義如下:
struct sembuf
{
short int sem_num; //訊號量元素個數
short int sem_op; //訊號量元素上的操作
short int sem_flg; //操作選項
}
在結構sembuf中,sem_num表示訊號量元素的個數,sem_op表示在訊號量元素上執行的特別操作,sem_flg表示操作選項的標誌。如果sem_op為正數,semop函式將該值加到相應的訊號量元素中,並喚醒所有等待元素增1的程序。如果sem_op為0而訊號量的值不為0, semop將阻塞呼叫程序並增加那個元素的等零程序個數。如果sem_op為負數,semop將該值加到相應的訊號量元素中(只要結果不為負數),如結果為負數,semop將阻塞程序等待訊號量元素值增加;如值為0,semop將喚醒等零程序。
上面的描述假設sem_flg為0。如果sem_flg&IPC_NOWAIT為真,呼叫不會阻塞,而是返回-1並設定error為 EAGAIN。如果sem_flg&SEM_UNDO為真,函式也將為程序修改訊號量的調整值。這個調整值允許程序在退出時恢復它在訊號量上的作用。
下面的程式給出了關於訊號量集的系統呼叫semget,semctl和semop的基本用法。
#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/ipc.h>
main()
{
int semid,pid,I,j;
static struct sembuf lock={0,-1,SEM_UNDO};
static struct sembuf unlock={0,1,SEM_UNDO|IPC_NOWAIT};
if((semid=semget(998,1,IPC_CREAT|IPC_EXCL|0666))==-1)
{
printf(“error:semget!/n”);
exit(1);
}
if(semctl(semid,0,SETVAL,1)==-1)
{
printf(“error:semctl!/n”);
exit(1);
}
setbuf(stdout,(char *)NULL);
for(i=0;i<3;i++)
{
if(fork()==0)
{
if((semid=semget(998,1,0))==-1)
{
printf(“error:semget!/n”);
exit(1);
}
for(j=0;j<3;j++)
{
sleep(i);
if(semop(semid,&lock,1)==-1)
{
printf(“error:semop!/n”);
exit(1);
}//if lock
printf(“process %d get into critical section!/n”,getpid());
sleep(1);
printf(“process %d left critical section!/n”,getpid());
if(semop(semid,&unlock,1)==-1)
{
printf(“error:semop!/n”);
exit(1);
}
}//for j
exit(0);
}//if fork
}//for i
for(i=0;i<3;i++)
wait(NULL);
if(semctl(semid,0,IPC_RMID,0)==-1)
{
printf(“error:semctl!/n”);
exit(1);
}
exit(0);
}
訊號量與訊息類似,也是程序間通訊的一種方法。我們在這裡講的訊號量,實際上是一個包含訊號量元素陣列的訊號量集。訊號量元素與E.W.Dijkstra提出的整數訊號量相對應。在一個單系統呼叫中,程序可在完整的訊號量集上操作。
訊號量集的內部表示和各自訊號量元素不是直接可以訪問的,但每個訊號量元素必須包括下列各項:
l 一個標識訊號量元素的非負整數
l 最後操作訊號量元素的程序ID
l 等待訊號量元素值加1的程序數
l 等待訊號量元素值等於0的程序數
訊號量操作允許一個程序阻塞直到訊號量元素值為0或者直到它變為正數。每個元素具有兩個相關聯的佇列:一個是等待訊號量元素值加1的程序佇列,另一個是等待訊號量元素值等於0的程序佇列。
1、 semget函式
系統呼叫semget用來建立一個訊號量集並將每個元素初始化為0
#include<sys/ipc.h>
#include<sys/sem.h>
int semget(key_t key, int nsems, int semflg );
函式semget有3個引數。第1個引數為標識訊號量集的關鍵字,程式指定關鍵字的方法有三種:使用IPC_PRIVATE讓系統產生一個關鍵字、挑選一個隨機數,或者是使用ftok從檔案路徑名中產生一個關鍵字。第2個引數為訊號量集中的元素個數。第3個引數為訊號量存取權標誌與建立標誌,該引數的低9位是訊號量的存取權標誌;建立標誌有2個,IPC_CTEAT和IPC_EXCL。IPC_CREAT表示如果訊號量集不存在,則建立它; IPC_EXCL表示只有在訊號量集不存在的情況下,新的訊號量集才會被建立,否則semget返回-1,並設定errno。如果這兩個標誌聯合使用,則功能如同O_EXCL標誌於open。
函式semget呼叫成功時返回一個用於以後semctl等操作的整數控制代碼,失敗時返回-1。
在指定訊號量集的關鍵字時,我們可以使用ftok根據檔案路徑名產生一個關鍵字。
#include<sys/ipc.h>
key_t ftok(const char * pathname, int proj_id);
函式ftok的第1個引數為檔案路徑名,該檔案必須存在且程序對該檔案有訪問權。第2個引數為程式設計師指定的一個整數ID。該函式成功呼叫時返回一個關鍵字,如呼叫失敗,則返回-1。
2、 semctl函式
系統呼叫semctl可以對訊號量進行很多控制。
#include<sys/ipc.h>
#include<sem.h>
int semctl(int semid, int semnum, int cmd, /*union senum arg*/…);
函式的第1個引數為訊號量集的控制代碼。第2個引數指定訊號量集中的元素。第3個引數為執行的控制命令,常見的命令如下表:
命令名稱
表示的含義
GETVAL
獲得一個指定訊號量的值
GETPID
獲得操作此元素的最後程序的ID
GETNCNT
獲得等待元素增1的程序數
GETZCNT
獲得等待元素變為0的程序數
SETVAL
設定一個指定訊號量元素的值為arg.val
IPC_RMID
刪除一個訊號量
IPC_SET
設定訊號量的許可權
函式semctl在出現錯誤時返回-1並設定erro。當呼叫成功時,其返回值決定於引數cmd,當cmd為GETVAL、GETPID、GETNCNT或GETZCNT時,函式返回相應的值,當cmd為別的值時,返回0。
union senum定義可直接包含在程式中,因為系統的標頭檔案中並沒有定義它。它的定義如下:
union senum
{
int val;
struct semid_ds *buf;
ushort *array;
};
union senum中提到的semid_ds結構定義如下:
struct semid_ds
{
struct ipc_perm sem_perm; /*operation permission struct*/
time_t sem_otime; /*last semop() time*/
time_t sem_ctime; /*last time changed by semctl()*/
struct sem*sembase; /*ptr to first semaphore in array*/
struct sem_queue *sem_pending; /*pending operations*/
struct sem_queue *sem_pending_last; /*last pending operation*/
struct sem_undo *undo; /*undo requests on this array*/
unsigned short int sem_nsems; /*number of semaphores in set*/
};
3、 semop函式
系統呼叫semop可以對訊號量增1、減1或測試其是否為0。
#include <sys/ipc.h>
#include <sys/sem.h>
int sempo(int semid, struct sembuf *sops, unsigned int nsops);
函式semop的第1個引數為semget返回的控制代碼,第2個引數指向元素運算元組,第3個引數指定在陣列中元素操作的個數。
函式成功呼叫時返回0,失敗時返回-1。如果時被訊號中斷,則返回-1,同時設定errno為EINTR。
結構體sembuf的定義如下:
struct sembuf
{
short int sem_num; //訊號量元素個數
short int sem_op; //訊號量元素上的操作
short int sem_flg; //操作選項
}
在結構sembuf中,sem_num表示訊號量元素的個數,sem_op表示在訊號量元素上執行的特別操作,sem_flg表示操作選項的標誌。如果sem_op為正數,semop函式將該值加到相應的訊號量元素中,並喚醒所有等待元素增1的程序。如果sem_op為0而訊號量的值不為0, semop將阻塞呼叫程序並增加那個元素的等零程序個數。如果sem_op為負數,semop將該值加到相應的訊號量元素中(只要結果不為負數),如結果為負數,semop將阻塞程序等待訊號量元素值增加;如值為0,semop將喚醒等零程序。
上面的描述假設sem_flg為0。如果sem_flg&IPC_NOWAIT為真,呼叫不會阻塞,而是返回-1並設定error為 EAGAIN。如果sem_flg&SEM_UNDO為真,函式也將為程序修改訊號量的調整值。這個調整值允許程序在退出時恢復它在訊號量上的作用。
下面的程式給出了關於訊號量集的系統呼叫semget,semctl和semop的基本用法。
#include <stdio.h>
#include <stdlib.h>
#include <sys/sem.h>
#include <sys/ipc.h>
main()
{
int semid,pid,I,j;
static struct sembuf lock={0,-1,SEM_UNDO};
static struct sembuf unlock={0,1,SEM_UNDO|IPC_NOWAIT};
if((semid=semget(998,1,IPC_CREAT|IPC_EXCL|0666))==-1)
{
printf(“error:semget!/n”);
exit(1);
}
if(semctl(semid,0,SETVAL,1)==-1)
{
printf(“error:semctl!/n”);
exit(1);
}
setbuf(stdout,(char *)NULL);
for(i=0;i<3;i++)
{
if(fork()==0)
{
if((semid=semget(998,1,0))==-1)
{
printf(“error:semget!/n”);
exit(1);
}
for(j=0;j<3;j++)
{
sleep(i);
if(semop(semid,&lock,1)==-1)
{
printf(“error:semop!/n”);
exit(1);
}//if lock
printf(“process %d get into critical section!/n”,getpid());
sleep(1);
printf(“process %d left critical section!/n”,getpid());
if(semop(semid,&unlock,1)==-1)
{
printf(“error:semop!/n”);
exit(1);
}
}//for j
exit(0);
}//if fork
}//for i
for(i=0;i<3;i++)
wait(NULL);
if(semctl(semid,0,IPC_RMID,0)==-1)
{
printf(“error:semctl!/n”);
exit(1);
}
exit(0);
}