目录:
3.信号量
- 命令
ipcs //查看消息队列、信号量、共享内存
ipcrm -s semid //删除信号量 semid是信号量的ID
-
信号量是一个特殊的变量,一般取正数值。它的值代表允许访问的资源数目,只是一种同步机制,不能实现进程间的数据共享
-
获取资源时,需要对信号量的值进行原子减一,该操作被称为 P 操作。当信号量值为 0 时,代表没有 资源可用,P 操作会阻塞。
-
释放资源时,需要对信号量的值进行原子加一,该操作被称为 V 操作。信号量主要用来同步进程。信号量的值如果只取 0,1,将其称为二值信号量。如果信 号量的值大于 1,则称之为计数信号量。
-
临界资源:同一时刻,只允许被一个进程或线程访问的资源
-
临界区:访问临界资源的代码段
-
信号量:多个进程 访问相同资源 冲突 红绿灯
-
特殊的变量 值>= 0 值可用资源的数目
试衣间: 3个 信号量值: 3 -
API接口函数介绍
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
//semget()创建或者获取已存在的信号量
int semget(key_t key, int nsems, int semflg);
/*
semget()成功返回信号量的 ID, 失败返回-1
key:两个进程使用相同的 key 值,就可以使用同一个信号量
nsems:内核维护的是一个信号量集,在新建信号量时,其指定信号量集中信号量的个数
semflg 可选: IPC_CREAT IPC_EXCL
*/
//semop()对信号量进行改变,做 P 操作或者 V 操作
int semop(int semid, struct sembuf *sops, unsigned nsops);
/*
semop()成功返回 0,失败返回-1
struct sembuf
{
unsigned short sem_num; //指定信号量集中的信号量下标
short sem_op; //其值为-1,代表 P 操作,其值为 1,代表 V 操作
short sem_flg; //SEM_UNDO IPC_NOWAIT 一般信号量为0,p操作阻塞,使用该则不阻塞返回一个错误
};
nsops sembuf结构体数组的大小
*/
//semctl()控制信号量
int semctl(int semid, int semnum, int cmd, ...);
/*
semctl()成功返回 0,失败返回-1
cmd 选项: SETVAL(初始化) IPC_RMID(删除)
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *_buf;
};
*/
#include "sem.h" //sem.c
static int semid; //静态全局变量 --- .data区 本文件有效
void sem_init(){
semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600); //1234编号 1:1个信号量
if(semid == -1){ // 创建失败(只需要获取)
semid = semget((key_t)1234,1,0600); //获取
if(semid == -1) exit(1);
}
else{
union semun a;
a.val = 1;
if(semctl(semid,0,SETVAL,a) == -1){ //0号下标
perror("semctl error");
exit(1);
}
}
}
void sem_p(){
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1; //获取资源
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1) == -1){
perror("semop err");
exit(1);
}
}
void sem_v(){
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1; //释放资源
buf.sem_flg = SEM_UNDO;
if(semop(semid,&buf,1) == -1){
perror("semop err");
exit(1);
}
}
void sem_destory(){
if(semctl(semid,0,IPC_RMID) == -1){
perror("semctl rm error");
exit(1);
}
}