Linux18 进程间通信(三)信号量
信号量:进程同步控制。信号量用来同步进程,像红绿灯控制东西、南北车辆一样。引入信号量会使程序的性能降低,但不同步程序的安全性得不到保障。
进程同步:进程协同工作
进程异步:进程独立运行,互不干扰,但两个进程之间是有关系的,没有关系的进程叫做并发执行,需要内核机制来通知(信号就是一种很好的通知方式。)
临界资源:同一时刻只能被一个进程访问使用的资源,临界资源可以有多份。
临界区:访问临界资源的代码区域。
原子操作:不能被终止的,不能被暂停的操作是原子操作。是一种最小的操作。要么做,要么做完,不可出现中间状态。
i++不是原子操作。
PV操作:是特殊的变量,值的改变是原子操作。P操作:减一,获取资源,如获取不到(信号量为0),就要等待,所以可能阻塞。V操作:加一,释放资源,不会阻塞。
信号量:类似于计数器,>0临界资源可用,申请资源进程执行P操作,则进程会被阻塞。
信号量的内核对象维护的是信号量集 信号量的数组
1、创建或者获取信号量
int semget((key_t)key,int nsems,int flag);
nsems:创建时,制定信号量集中信号量的个数
2、控制信号量,初始化或者移除信号量的值
int semctl(int semid,int semnum,int cmd,union semun);
union semun
{
int val;
struct semid_ds* buf;
short* array;
}
3、PV操作(改信号量值)
int semop(int semid, struct sembuf buff[],int size);
struct sembuf
{
short sem_num;
short sem_op;
short sem_flg;
}
封装pv
sem.h
# include <sys/sem.h>
union semun
{
int val;
};
void Sem_init();
void Sem_p();
void Sem_v();
void Sem_destory();
sem.c
# include "sem.h"
static int semid;
void Sem_init()
{
semid = semget((key_t)1234,1,IPC_CREAT|IPC_EXCL|0600);
if(semid == -1)
{
semid = semget((key_t)1234,1,0600);
if(semid==-1)
{
perror("semget error");
return;
}
}
else
{
union semun a;
a.val=1;
if(semctl(semid,0,SETVAL,a)==-1)
{
perror("semctl error");
}
}
return ;
}
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 p error");
}
}
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 v error");
}
}
void Sem_destory()
{
if(semctl(semid,0,IPC_RMID)==-1)
{
perror("semcrl error");
}
}