信号量
信号量是記錄和統計臨界資源數目的計數器;
(一)建立信号量:
信号量的申請是以信号量集為機關的;
int semget(key_t key,int nsems,int semflag);
傳回值:信号量集的辨別符;
參數:
key:用key_t ftok(const char* pathname,int proj_id)來擷取;
nsems:表示要建立的這個信号量集中信号量的個數;
semflag:(1)IPC_CREAT:建立這個信号量集,若沒有就建立,若有則打開即可;
(2)IPC_CREAT | IPC_EXCL:若建立的信号量不存在,則:建立;若建立的信号量存在,則:錯誤傳回;
(二)初始化信号量
int semctl(int semid,int semnum, int cmd,);
傳回值:(1)傳回值為0表示初始化成功;
(2)初始化失敗,傳回-1;
參數:
semid:要初始化的信号量所在的信号量集的id;
semnum:要初始化的信号量是該信号量集的第幾個信号(從0開始);
cmd:設為SETVAL表示對信号量進行初始化;
(三)删除信号量
int semctl(int semid,int semnum,int cmd)
傳回值:(1)傳回值為0表示删除信号量成功;
(2)傳回值為-1表示删除失敗;
參數:
semid:要删除的信号量集的id;
semnum:設定為0;
cmd:設定為IPC_RMID表示删除操作;
(四)P操作
int semop(int semid,struct sembuf*sops,unsigned nsops)
傳回值:(1)傳回值為0,表示操作成功;
(2)傳回值為-1,表示操作成功;
參數:
semid:為操作的信号量所處的信号量集的id;
sops:所操作的信号量所在的數組;
struct sembuf
{
unsigned short sem_num; //操作信号量集中的哪一個信号量
short sem_op; //對于信号量執行什麼操作
short sem_flg;
}
sops.sem_op = -1,位P操作;
nsops:操作的信号量的數目;
(五)V操作
int semop(int semid,struct sembuf*sops,unsigned nsops)
傳回值:(1)傳回值為0,表示操作成功;
(2)傳回值為-1,表示操作失敗;
參數:semid:為操作的信号量所處的信号量集的id;
sops:所操作的信号量所在的數組;
sops.sem_op = 1,位V操作;
nsops:操作的信号量的數目
common.h
#ifndef _COMMON_H_
#define _COMMON_H_
#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#define PATHNAME "/home/cm/code"
#define PROJ_ID 0x6666
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *_buf;
};
int Creat_Sem();
int Get_Sem();
int Init_Sem(int sem_id,int val);
int Destory_Sem(int sem_id);
int P(int sem_id,int who);
int V(int sem_id,int who);
#endif
common.c
#include"common.h"
static int CommonCreat_Sem(int flags)
{
key_t key = ftok(PATHNAME,PROJ_ID);
int sem_id =0;
if(key<0)
{
perror("ftok");
return -1;
}
else
{
sem_id = semget(key,1,flags);
if(sem_id < 0)
{
perror("semget");
return -2;
}
}
return sem_id;
}
int Creat_Sem()
{
int sem_id = CommonCreat_Sem(IPC_CREAT | IPC_EXCL | 0666);
return sem_id;
}
int Get_Sem()
{
int sem_id = CommonCreat_Sem(IPC_CREAT);
return sem_id;
}
int Init_Sem(int sem_id,int Val)
{
union semun _un;
_un.val = Val;
int ret = semctl(sem_id,0,SETVAL,_un);
if(ret < 0) //init failed
{
perror("semctl");
return -1;
}
return 0; //init success
}
int Destory_Sem(int sem_id)
{
int ret = semctl(sem_id,0,IPC_RMID);
if(ret < 0)
{
perror("semctl");
return -1;
}
return 1;
}
static int CommonPV(int sem_id,int who,int op)
{
struct sembuf _sf;
_sf.sem_num = who;
_sf.sem_op = op; //P:-1;V:1
_sf.sem_flg = 0;
int ret = semop(sem_id,&_sf,1);
if(ret<0)
{
perror("semop");
return -1;
}
return 0;
}
int P(int sem_id,int who)
{
return CommonPV(sem_id,who,-1);
}
int V(int sem_id,int who)
{
return CommonPV(sem_id,who,1);
}
Makefile
test:test_sem.c common.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f test
test_sem.c
#include"common.h"
int main()
{
int sem_id = Creat_Sem();
int val = 1;
Init_Sem(sem_id,val);
int pid = fork();
if(pid == 0)
{
//child
while(1)
{
P(sem_id,0);
printf("A");
fflush(stdout);
usleep(123456);
printf("A");
fflush(stdout);
usleep(123456);
V(sem_id,0);
}
}
else
{
while(1)
{
P(sem_id,0);
printf("B");
fflush(stdout);
usleep(123456);
printf("B");
fflush(stdout);
V(sem_id,0);
}
wait(NULL);
}
printf("\n");
Destory_Sem(sem_id);
return 0;
}
注;
struct sembuf
{
unsigned short sem_num; //操作信号量集中的哪一個信号量
short sem_op; //對于信号量執行什麼操作
short sem_flg;
}
sem_flg:
sem_flg是用來說明semop的操作方式;
(1)IPC_NOWAIT:對信号的操作不成功時,semop不會阻塞,并且立即傳回。
(2)SEM_UNDO:程式結束的時候,對于資料進行復原,避免造成資料的二義性;
對于二進制信号量來說,為了防止造成死鎖問題,必須在程式退出時,對于資料進行復原,防止造成二義性;産生結果的不确定性;
作者水準有限,若有問題,請留言,謝謝!!!