信号量简介
信号量是一个计数器,用于进程和线程之间同步问题,也用于对临界资源访问问题。临界资源可以是一段代码或一个参数等。信号量值大于等于0,表示可访问临界资源的进程,小于0表示等待使用临界资源的进程。即为信号量是大于等于或小于0的数,赋予某个进程或线程访问或执行某段程序或调用某个参数的权限。
信号量的相关函数
创建信号量
int semget(key_t key, int nsems, int semflg);
参数:
key:键值
nsems:创建信号量集中信号量的个数,只在创建信号量时有用
semflg:
0:获取信号量级标识,若不存在,则报错
IPC_CREAT:不存在创建信号量,存在则返回
IPC_EXCL:与IPC_CREAT连用,若不存在,则创建,存在则报错
返回值:
成功执行返回信号量标识符,失败返回-1
创建信号量受到系统信息的影响
SEMMNI:系统中信号量的总数最大值
SEMMSL:每个信号量中信号量元素的个数最大值
SEMMNS:系统中素有信号量中的信号量元素的总数最大值
信号量初始化
int semctl(int semid, int semnum, int cmd, ...);
参数:
semid:信号量标识
semnum:信号量集数组的下标,表示某一个信号
cmd:
IPC_STAT从信号量集上检索semid_ds结构,并存到semun联合体参数的
成员buf的地址中
IPC_SET设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从
semun的buf中取出值
IPC_RMID从内核中删除信号量集合
GETALL从信号量集合中获得所有信号量的值,并把其整数值存到semun
联合体成员的一个指针数组中
GETNCNT返回当前等待资源的进程个数
GETPID返回最后一个执行系统调用semop()进程的PID
GETVAL返回信号量集合内单个信号量的值
GETZCNT返回当前等待100%资源利用的进程个数
SETALL与GETALL正好相反
SETVAL用联合体中val成员的值设置信号量集合中单个信号量的值
union semun
{
short val; /*SETVAL用的值*/
struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds结构*/
unsigned short* array; /*SETALL、GETALL用的数组值*/
struct seminfo *_buf; /*为控制IPC_INFO提供的缓存*/
}
struct semid_ds
{
struct ipc_perm sem_perm; //权限相关信息
time_t sem_otime; //最后一次semop()的信息
tien_t sem_ctime; //最后一次状态改变时间
unsigned short sem_nsems; //信号量元素个数
}
返回值:
成功执行返回-1,失败返回-1
PV操作
int semop(int semid, struct sembuf *sops, unsigned nsops);
参数:
semid:信号量标识符
nsops:结果体数组元素个数(有多个信号时创建,需操作时,使用数组分配操
作,此处为操作信号的个数)
sops:
struct sembuf
{
short semnum; /*信号量集合中的信号量编号,0代表
第1个信号量*/
short val;
/*
l>0:V操作信号量值加val,进程释放控制
的资源
<0:P操作信号量值减val,(semval-val)
<0(semval为该信号量值),则调用进程阻塞
IPC_NOWAIT:不会睡眠,进程直接返回
EAGAIN错误
=0:阻塞等待信号量为0,调用进程进入睡
眠状态,直到信号值为0
IPC_NOWAIT:进程不会睡眠,直接返回
EAGAIN错误
short flag; /*
0;设置信号量的默认操作
IPC_NOWAIT:设置信号量操作不等待
SEM_UNDO:内核记录调用进程的UNDO
记录,进程崩崩溃,根据UNDO记录恢复信号
量的计数值
*/
}
返回值:
成功执行返回0,失败返回-1
demo1:
1.创建父子进程
2.子进程获取信号执行权限,打印son,归还权限
3.父进程获取信号执行权限,打印father,归还权限
代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
void get_atu(int semid)
{
struct sembuf sops;
sops.sem_num = 0;
sops.sem_op = 1;
sops.sem_flg = SEM_UNDO;
semop(semid,&sops,1);
}
void return_atu(int semid)
{
struct sembuf sops;
sops.sem_num = 0;
sops.sem_op = -1;
sops.sem_flg = SEM_UNDO;
semop(semid,&sops,1);
}
void result()
{
key_t key;
int semid;
int pid;
key = ftok(".",128);
if(key == -1)
{
printf("create key fail\n");
perror("why");
exit(-1);
}
semid = semget(key,1,IPC_CREAT|0777);
if(semid == -1)
{
printf("create sign fail\n");
perror("why");
exit(-1);
}
union semun init_sign;
init_sign.val = 0;
semctl(semid,0,SETVAL,init_sign);
pid = fork();
if(pid == 0)
{
get_atu(semid);
printf("son\n");
return_atu(semid);
}
else if(pid > 0)
{
get_atu(semid);
printf("father\n");
return_atu(semid);
}
else
{
printf("create fork fail\n");
perror("why");
exit(-1);
}
}
int main()
{
result();
return 0;
}
结果示例:
demo2:
1.编写程序,创建共享内存,写入hello word
2.编写程序,获得权限信号,读取共享内存,释放权限
代码示例:
create_shm
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
void result()
{
key_t key;
int shmid;
char *context = "hello word";
char *shmaddr = NULL;
key = ftok(".",128);
if(key == -1)
{
printf("crate key fail\n");
perror("why");
exit(-1);
}
shmid = shmget(key,20,IPC_CREAT|0777);
if(shmid == -1)
{
printf("crate show memory fail\n");
perror("why");
exit(-1);
}
shmaddr = shmat(shmid,0,0);
if(shmaddr == NULL)
{
printf("show memory mappingfail\n");
perror("why");
exit(-1);
}
strcpy(shmaddr,context);
sleep(10);
shmctl(shmid,IPC_RMID,NULL);
shmdt(shmaddr);
}
int main()
{
result();
return 0;
}
signal_shm
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
void get_key(int semid)
{
struct sembuf sops;
sops.sem_num = 0;
sops.sem_op = 2;
sops.sem_flg = SEM_UNDO;
semop(semid,&sops,1);
}
void return_key(int semid)
{
struct sembuf sops;
sops.sem_num = 0;
sops.sem_op = -2;
sops.sem_flg = SEM_UNDO;
semop(semid,&sops,1);
}
void read_shm(int key)
{
int shmid;
char *shmaddr = NULL;
shmid = shmget(key,20,IPC_CREAT|0777);
shmaddr = shmat(shmid,0,0);
printf("show memory : %s\n",shmaddr);
shmctl(shmid,IPC_RMID,NULL);
}
void result()
{
key_t key;
int semid;
key = ftok(".",128);
if(key == -1)
{
printf("create key fail\n");
perror("why");
exit(-1);
}
semid = semget(key,1,IPC_CREAT|0777);
union semun init_sem;
init_sem.val = -1;
semctl(semid,0,SETVAL);
get_key(semid);
read_shm(key);
return_key(semid);
}
int main()
{
result();
return 0;
}
结果示例: