【Linux学习笔记41】SYS-V 进程间的通信(三)(信号量)

信号量的简介

信号量是代表一类资源。在编程中,如果要使用资源,首先要知道是否有资源可用。以之前的共享内存为例子,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);
}

代码运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值