1、概述:System V訊號量用三個函數,semget,semop,semctl,分別是訊號量集的奪取,操作,控制。其操作對象是訊號量集合,semop操作的集合中,這些對象要麼全部成功,要麼全都不成功。
2、訊號量的銷毀,因為System V訊號量是核心持久性的,也就是說銷毀方式有兩種,要麼在進程中顯式銷毀,要麼只有當核心關閉時才銷毀。
3、核心中與訊號量有關的資料結構。
核心中維持一份全域的struct semid_ds數組,semid_ds是訊號量集合的結構。semget函數返回這個訊號量集合在數組中的小標。
struct semid_ds
{
struct ipc_perm sem_perm; //該訊號量集合的操作許可許可權
struct sem *sem_base; //該數組的元素是:該集合包含的訊號量的結構。
ushort sem_nsems; //sem_base數組的個數
time_t sem_otime; //最後一次成功修改該訊號量數組的時間。
time_t sem_ctime; //成功建立的時間
};
struct sem
{
ushort semval; //訊號量的當前值
short sempid; //最後一次返回該訊號量的進程的id號
ushort semncnt; //等待semval大於當前值的進程的個數
ushort semzcnt; //等待semval變成0的進程的個數
};
4、int shmget(key_t key, int nsems, int flag); 傳回值是訊號量標示符。
key: key_t是int型的,這個是一個整數,要保證核心唯一性。
nsems:該集合包含的訊號量的個數。
flag:建立的許可權, 可以使一些讀寫權限與:IPC_CREAT ( | IPC_EXCL )的按位或。
當該函數成功時,linux核心中的semval值為0,但是該值的初始化沒有可移植性(就是說不能保證所有系統都能初始化該值)
這個函數的作用:建立或者開啟訊號量集。
5、int semop(int semid, struct sembuf *opsptr, size_t nops);
semid:是semget返回的semid號。
nops:是數組opsptr的個數。
opsptr是操作結構的數組
struct sembuf
{
short sem_num; //訊號量在semid集合中的序號:0到nsems - 1;
short sem_op; //操作
short sem_flag; //0, IPC_NOWAIT, SEM_UNDO
};
其中,sem_op值如下:
a、如果sem_op大於0,表示sem_num訊號量所代表的資源的釋放,semval += sem_op;
b、如果sem_op小於0,表示sem_num訊號量所代表資源的分配,具體是:如果semval 大於等於 sem_op的絕對值,則semval -= sem_op絕對值;否則,阻塞知道條件滿足
c、如果sem_op等於0,表示直到semval 等於0時才返回。
6、int semctl(int semid, int semnum, int cmd, ../* union semun arg */);
其中semid是訊號量集合,semnum是訊號在集合中的序號,
union semun
{
int val; /* cmd == SETVAL */
struct semid_ds *buf /* cmd == IPC_SET或者 cmd == IPC_STAT */
ushort *array; /* cmd == SETALL, 或 cmd = GETALL */
};
cmd取值如下:
GETVAL, SETVAL : semid集合中semnum訊號量當前的semval值
GETALL,SETALL :semid集合中所有訊號量的值。
IPC_RMID:刪除semid訊號量集
GETPID:返回最後成功操作該訊號的進程號。
IPC_STAT:返回semid集合中的struct semid_ds結構。
7、例子1:PV原語操作:
int sem_id = 0; /* semget的傳回值,全域 */
#define MUTEX 0 /* 用於返回臨界區的訊號量在集合中的序數 */
#define NUM_SEM 1 /* 集合中訊號量的個數 */
#define SEM_KEY 0x11223344 /*保證核心中的唯一性 */
void P(int sem_num)
{
struct sembuf sem;
sem.sem_num = MUTEX;
sem.sem_op = -1;
sem.sem_flg = 0;
if( -1 == semop(sem_id, &sem, 1) )
{
/* 錯誤處理 */
}
}
void V(int sem_num)
{
struct sembuf sem;
sem.sem_num = MUTEX;
sem.sem_op = 1;
sem.sem_flg = 0;
if( -1 == semop(sem_id, &sem, 1) )
{
/* 錯誤處理 */
}
}
主函數:
int main()
{
...
int semid;
....
semid = semget(SEM_KEY, 0, 0); /* panduan 判斷該型號量組是否已經存在 */
if( -1 == semid )
{
semid = semget(SEM_KEY, NUM_SEM, IPC_CREAT | IPC_EXCL | 0666);
if( -1 == semid)
{
/* 錯誤處理 */
}
else
{
semctl(sem_id, MUTEX, SETVAL, 1); /* 初始值為1。錯誤處理略 */
}
}
...
P(MUTEX);
/* 臨界區程式碼片段 */
V(MUTEX);
...
}