信号量的简介
信号量是代表一类资源。在编程中,如果要使用资源,首先要知道是否有资源可用。以之前的共享内存为例子,P1往共享内存写入数据的操作首先要申请资源,申请成功后才能往共享内存中写入数据,那么写入成功后,整个共享内存中的资源就会减一。那么信号量就是指这个共享内存中的资源。
- P1写入数据到SHM,首先要申请空间:P(s1)
- P1申请资源成功,写入数据到SHM:V(s2)
- P2申请从SHM读出数据:P(s2)
- P2申请数据成功,释放SHM空间:V(s2)
- 由上面的循环,可以逐步形成一个同步
信号量的申请原理解剖
- 一个SYS-V(系统五)的信号量是一个集合,一个信号量可以包含多个信号量元素,这里以四个为例子
- 一个信号量元素的空间可以自定义,假设s0空间为2,等等等等
- 那么当进程申请s0号的信号量元素的大小为2,s1号的信号量元素的大小为1时,首先会检查大小是否符合申请,申请成功后,信号量中的大小也会随之减少。
测试共享内存中读写操作是否能够同步
在没有加信号量的情况下:
P1往共享内存中依次写入“0123456789”
P2从共享内存中读出:
可以看到没有信号量的代码,P1,P2并不能像我们想象中配合的如此的好,这就是信息的互斥,不能同步。
编写信号量的代码保证进程通信同步
1.创建信号量:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
2.初始化信号量:
int semctl(int semid, int semnum, int cmd, ...);
3.申请资源,释放资源:
int semop(int semid, struct sembuf *sops,
unsigned nsops);
整体代码:pro1:
#include "myhead.h"
int main(int argc, char **argv)
{
int shmid = shmget(ftok(".",1),SHMSIZE,IPC_CREAT | 0666);
char *addr = shmat(shmid , NULL , 0);
int semid = semget(ftok(".",2),2,IPC_CREAT |IPC_EXCL| 0666); //创建信号量KEY为2,信号量元素为2
if (semid>0)
{
//对信号量初始化
seminit(semid,DATA,0);
seminit(semid,SPACE,1);
}
else
{
semid = semget(ftok(".",2),2,0666);
}
char *msg = "0123456789";
int i = 0;
while (1)
{
sem_p(semid,SPACE); //申请空间资源 P操作
memcpy(addr,msg+i,1);
i = (i+1) % 10;
sem_v(semid,DATA);//释放数据 V操作
}
return 0;
}
pro2:
#include "myhead.h"
int main(int argc, char **argv)
{
int shmid = shmget(ftok(".",1),SHMSIZE,IPC_CREAT | 0666);
char *addr = shmat(shmid , NULL , 0);
int semid = semget(ftok(".",2),2,IPC_CREAT |IPC_EXCL | 0666);
if (semid>0)
{
seminit(semid,DATA,0); //初始化只能执行一遍,如果信号量是自己创建则初始化,如果不是则不初始化
seminit(semid,SPACE,1);
}
else
{
semid = semget(ftok(".",2),2,0666);
}
while (1)
{
sem_p(semid,DATA); //申请数据
fprintf(stderr,"%c",*addr);
sem_v(semid,SPACE); //释放空间
}
return 0;
}
头文件:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <fcntl.h>
#define DATA 0 //设置第0个元素代表数据
#define SPACE 1 //设置第1个元素代表空间
#define SHMSIZE 2
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
struct seminfo *__buf;
};
void seminit(int semid , int semnum , int val )
{
union semun a; //a的联合体要自己定义
a.val = val;
semctl(semid, semnum,SETVAL,a);
}
void sem_p(int semid ,int semnum) //P操作
{
struct sembuf a[1];
a[0].sem_num = semnum;
a[0].sem_op = -1; //减少一个资源
a[0].sem_flg = 0;
semop(semid,a,1);
}
void sem_v(int semid ,int semnum) //V操作
{
struct sembuf a[1];
a[0].sem_num = semnum;
a[0].sem_op = +1; //增加一个数据
a[0].sem_flg = 0;
semop(semid,a,1);
}
代码运行结果: