进程第三天———进程间的通信方式

25 篇文章 0 订阅
2 篇文章 0 订阅

信号:
同步:发送方发送数据,等待接受方响应之后才发下一个数据包的通讯方式
异步:发送方发送数据,不等待接送方发回相应,接着发送下一个数据包的通讯方式

1.特点:
信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式

2.基本概念:
发送信号:产生信号的方式有很多种,
(1).一个进程可以给一个进程发送一个特定信号, kill -9 进程ID号
(2).内核可以向用户进程发送信号 管道断裂 alarm(2)
(3).组合键
ctrl + c— SIGINT
ctrl+z ----SIGSTOP
ctrl+\ —SIFQUIT
(4).自己可以给自己发送信号 raise()

接受信号后处理信号
(1).忽略信号
(2).使用默认方式处理
(3).捕获信号(安装信号):获得该信号之后,不让他执行默认的操作,可以去执行别的程序,
但有两个信号是不能被安装也不能被忽略,SIGSTOP SIGKILL
3.使用的函数:
#include <signal.h>
int raise(int sig);
在这里插入图片描述

#include <unistd.h>
参数1:秒数
时间到了之后内核会给程序发送SIGALRM
unsigned int alarm(unsigned int seconds);

在这里插入图片描述

#include <signal.h>

typedef void (*sighandler_t)(int);
参数1是要接收到信号的id
参数2:
(1).忽略该信号 SIG_IGN
(2). 使用默认处理方式 SIG_DFL
(3). 捕获处理(安装信号)

sighandler_t signal(int signum, sighandler_t handler); 捕获信号(安装信号)
接收到的信号之后,对信号进行处理:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

systemV IPC对象
ipcs -----查看系统5的IPC对象
1.特点:
每个IPC对象有唯一的ID值,由系统分配的
每个IPC对象有一个关联的key值(ftok函数)
key值为0表示私有对象,若key非0和ID值一一对应
2.获得key值
消息队列,共享内存都需要获得key值
在这里插入图片描述

#include <sys/types.h>
#include <sys/ipc.h>
参数1:path存在且可访问的文件路径
参数2: 不能为0
返回值:成功返回key值,失败返回-1
key_t ftok(const char *pathname, int proj_id);
3.消息队列:
在这里插入图片描述

1.特点:
1.是一种特殊的链表队列,满足先入先出
2.消息队列是按照类型来发送/接受信息
2.使用的函数
打开和创建消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
参数1:通过ftok获得key
参数2:
IPC_CREAT |0600如果key不存在,则创建,若存在,返回id中
IPC_EXCL 如果key在,返回失败
IPC_NOWAIT 非阻塞
返回值:成功返回消息队列代号.失败返回-1
int msgget(key_t key, int msgflg);

读写数据
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
参数1:msgget获得的id值
参数2:自定义的结构体,
struct msgBuf{
long mtype; 消息队列的类型
char mtext[100]; 数据
}
参数3:发送消息的字节数
参数4:0 消息发送成功返回,无空间阻塞

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数1:msgget获得的id值
参数2:自定义的结构体,
struct msgBuf{
long mtype; 消息队列的类型
char mtext[100]; 数据
}
参数3:发送消息的字节数
参数4:接送数据的类型
参数5: 消息发送成功返回,无空间阻塞

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
控制消息队列
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
参数1:msgget获得ip的值
参数2: IPC_RMID 删除
IPC_SET 设置参数
IPC_STAT 获得参数
参数3:一般为NULL
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//定义结构消息队列中的结构体数据类型并取别名

typedef struct msgbuf
{
	long mtype; //消息的类型
	char mtext[100]; //消息的数据
}Msg;

int main(void)
{
	//1.获得key值
	key_t key=0;

	key=ftok("./",1);
	if(key<0)
	{
		printf("key error");
		return -1;
	}
	printf("key=%d\n",key);

	//2.获得消息队列代号
	int msgid=0;

	msgid=msgget(key,IPC_CREAT|0600);
	if(msgid<0)
	{
		perror("msgget error");
		return -1;
	}

	Msg msgA,msgB;
	msgA.mtype=1;
	msgB.mtype=2;

	while(1)
	{
		printf("A:");
		scanf("%s",msgA.mtext);
		//将类型发送给对方
		//参数1:msgget获得id 参数2:发送数据的首地址,参数3:大小,参数4
		msgsnd(msgid,&msgA,sizeof(msgA),0);
		memset(&msgB,'\0',sizeof(msgB));
		msgrcv(msgid,&msgB,sizeof(msgB),msgB.mtype,0);
		printf("B:%s\n",msgB.mtext);
	}


	//删除ipcs
	//参数1:msgget获得的id
	//参数2:IPC_RMID 表示删除
	//参数3:NULL
	msgctl(msgid,IPC_RMID,NULL);


	return 0;
}


#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//定义结构消息队列中的结构体数据类型并取别名

typedef struct msgbuf
{
	long mtype; //消息的类型
	char mtext[100]; //消息的数据
}Msg;
int main(void)
{
	//1.获得key值
	//2.获得消息队列代号
	//3,读取消息
	//4.删除消息队列
	
	//1.获得key值
	key_t key=0;
	key=ftok("./",1);
	if(key<0)
	{
		perror("ftok error");
		return -1;
	}

	//2.获得消息队列代号
	int msgid=0;
	msgid=msgget(key,IPC_CREAT|0600);
	if(msgid<0)
	{
		perror("msgget error");
		return -1;
	}
	//3,读取消息
	Msg msgA;
	msgA.mtype=1;
	Msg msgB;
	msgB.mtype=2;
	while(1)
	{
		//参数1:msgget获得的id
		//参数2:读取结构体的地址
		//参数3:读取的大小
		//参数4:读取的类型
		//参数5:0
		memset(&msgA,'\0',sizeof(msgA));
		msgrcv(msgid,&msgA,sizeof(msgA),msgA.mtype,0);
		printf("A:%s\n",msgA.mtext);
		printf("B:");
		scanf("%s",msgB.mtext);
		msgsnd(msgid,&msgB,sizeof(msgB),0);
	}

	
	//4.删除消息队列
	msgctl(msgid,IPC_RMID,NULL);
}

4.共享内存
1.特点:
共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,
共享内存是在内核空间创建,需要将内核共享内存区映射到用户进程中
由于多个进程可同时访问共享内存,因此需要同步(信号量)和互斥机制来配合

2.使用的函数
shmget函数:
#include <sys/ipc.h>
#include <sys/shm.h>
/*
函数名:shmget
函数功能:获得共享内存
函数参数:key:共享内存的键值,多个进程可以通过它访问同一个共享内存。ftok()获得
其中有个特殊值 IPC_PRIVATE,用于创建当前进程的私有共享内存。
size:共享内存的大小
shmflg:同open()函数的权限位,也可以使用八进制表示法
IPC_CREAT|0666
不管是否已存在该块共享内存,则都会返回共享内存的ID,若不存在则新建
IPC_EXCL
不管有没有该块共享内存,返回-1
函数返回值:
成功:共享内存段标识符
失败:-1
*/
int shmget(key_t key, size_t size, int shmflg);
shmat函数:
#include <sys/types.h>
#include <sys/shm.h>
函数参数:
shmid:要映射的共享内存区标识符。
shmaddr:将共享内存映射到指定地址若为NULL,则表示系统自动分配地址,并把该段共享,内存映射到调用进程的地址空间)
shmflg:SHM_RDONLY:共享内存只读
默认0:共享内存可读可写
函数返回值:成功:被映射的段地址
出错:-1
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmdt函数:
#include <sys/types.h>
#include <sys/shm.h>

函数原型:int shmdt(const void *shmaddr);
函数参数:shmaddr:被映射的共享内存段地址
函数返回值:
成功:0
失败:-1
#include <sys/ipc.h>
#include <sys/shm.h>
函数原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);

函数参数: 参数1:shmid:要映射的共享内存区标识符。
参数2:
IPC_RMID 表示删除
IPC_SET 设置参数
IPC_STAT 获得参数
参数3:NULL
函数返回值:
成功:0
失败:-1

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
int main(void)
{
	//1.通过ftok获得key
	//2.创建共享内存 shmget
	//3.将共享内存映射到具体的进程空间  shmat
	//4.读写
	//5.分离共享内存
	//6.删除共享内存
	//1.通过ftok获得key
	key_t key=0;
	key=ftok("./",12);
	if(key<0)
	{
		perror("ftok error");
		return -1;
	}
	//2.创建共享内存 shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);
	if(shmid<0)
	{
		perror("shmget error");
		return -1;
	}
	//3.将共享内存映射到具体的进程空间  shmat
	char * pShm=NULL;
	pShm=shmat(shmid,NULL,0);
	//4.读写
	memset(pShm,'\0',pShm);
	strcpy(pShm,"helloworld");
	//5.分离共享内存
	shmdt(pShm);
	//6.删除共享内存
	shmctl(shmid,IPC_CREAT,NULL);
	return 0;
}

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(void)
{
	//1.通过ftok获得key
	//2.创建共享内存 shmget
	//3.将共享内存映射到具体的进程空间  shmat
	//4.读写
	//5.分离共享内存
	//6.删除共享内存
	//1.通过ftok获得key
	key_t key=0;
	key=ftok("./",12);
	if(key<0)
	{
		perror("ftok error");
		return -1;
	}
	//2.创建共享内存 shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);
	if(shmid<0)
	{
		perror("shmget error");
		return -1;
	}
	//3.将共享内存映射到具体的进程空间  shmat
	char * pShm=NULL;
	pShm=shmat(shmid,NULL,0);
	//4.读写

	sleep(5);
	printf("%s",pShm);
	//5.分离共享内存
	shmdt(pShm);
	//6.删除共享内存
	shmctl(shmid,IPC_CREAT,NULL);
	return 0;
}

5.信号量
共享内存------公共区域
1.实现进程间的同步
和共享内存配合使用,帮助共享内存实现同步
1 2 3 4 5 6 7 8
多个线程: 买菜----择菜 -----洗菜-----切菜----炒菜—端菜----收盘—洗盘

2.工作原理:
二值信号灯:
值为0或1。与互斥锁类似,资源可用时值为1,不可用时值为0。
计数信号灯:
值在0到n之间。用来统计资源,其值代表可用资源数
等待操作是等待信号灯的值变为大于0,然后将其减1;而释放操作则相反,用来唤醒等待资源的进程或者线程

2.使用的函数
sem_open:
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>

	sem_t *sem_open(const char *pathname, int oflag);
	/*
	 *函数名:sem_open
	 *函数功能:打开一个信号量,如果信号量不存在,则创建信号量
	 *函数参数:
	 *		const char *pathname:信号量的名字(标识)
	 *		int oflag:同文件IO的创建时的权限
	 *					O_CREAT | O_RDWR
	 *		mode_t mode:同文件权限
	 *		unsigned in value:信号量的初始值
	 *函数返回值:sem_t *:成功返回信号量操作对象的指针
	 */

sem_t *sem_open(const char pathname, int oflag, mode_t mode, unsigned int value);
sem_getvalue:
#include <semaphore.h>
/

*函数名:sem_getvalue
*函数功能:获取当前信号量的值
*函数参数:
* sem_t *sem:信号量的操作指针
* int *sval:存储信号量值得内存首地址
*函数返回值:int:成功返回0,失败返回-1
*/
int sem_getvalue(sem_t *sem, int sval);
sem_wait:
#include <semaphore.h>
/

*函数名:sem_wait
*函数功能:信号量值减一
*函数参数:sem_t *sem:信号量的操作指针
*函数返回值:int:成功返回0,失败返回-1
*/
int sem_wait(sem_t sem);
sem_post:
#include <semaphore.h>
/

*函数名:sem_post
*函数功能:信号量值加一
*函数参数:sem_t *sem:信号量的操作指针
*函数返回值:int:成功返回0,失败返回-1
*/
int sem_post(sem_t sem);
sem_close:
#include <semaphore.h>
/

*函数名:sem_close
*函数功能:关闭一个有名信号量
*函数参数:sem_t *sem:信号量的操作指针
*函数返回值:int:成功返回0,失败返回-1
*/
int sem_close(sem_t *sem);

注意:进程中使用的信号量,称之为有名信号量
	 编译时链接库 -lpthread

头文件.h

#ifndef _SHM_H
#define _SHM_H

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#endif

#include <stdio.h>
#include "shm.h"
#include <string.h>
int main(void)
{
	//1.通过ftok获得key
	//2.创建共享内存 shmget
	//3.将共享内存映射到具体的进程空间  shmat
	//4.读写
	//5.分离共享内存
	//6.删除共享内存
	//1.通过ftok获得key
	key_t key=0;
	key=ftok("./",12);
	if(key<0)
	{
		perror("ftok error");
		return -1;
	}
	//2.创建共享内存 shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);
	if(shmid<0)
	{
		perror("shmget error");
		return -1;
	}




	//3.将共享内存映射到具体的进程空间  shmat
	char * pShm=NULL;
	pShm=shmat(shmid,NULL,0);

	//1-1.打开信号登,设置初值 4
	
	 sem_t *mySem;
	 mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,5);
	 if(NULL==mySem)
	{
			perror("sem_open error");
	}
	



	while(1){
		sleep(3);	
		//1-2.获得当前信号量的值
		int sem_v;
		sem_getvalue(mySem,&sem_v);
	//	printf("sem_v=%d\n",sem_v);

		if(sem_v==5){
			//1-3.将信号量的值减1
			sem_wait(mySem);
			printf("%s\n",pShm);
			//4.读写
			memset(pShm,'\0',1024);
			strcpy(pShm,"买菜");
		}
	}
	//5.分离共享内存
	shmdt(pShm);
	//6.删除共享内存
	shmctl(shmid,IPC_CREAT,NULL);
	return 0;
}

#include <stdio.h>
#include "shm.h"
#include <string.h>
int main(void)
{
	//1.通过ftok获得key
	//2.创建共享内存 shmget
	//3.将共享内存映射到具体的进程空间  shmat
	//4.读写
	//5.分离共享内存
	//6.删除共享内存
	//1.通过ftok获得key
	key_t key=0;
	key=ftok("./",12);
	if(key<0)
	{
		perror("ftok error");
		return -1;
	}
	//2.创建共享内存 shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);
	if(shmid<0)
	{
		perror("shmget error");
		return -1;
	}




	//3.将共享内存映射到具体的进程空间  shmat
	char * pShm=NULL;
	pShm=shmat(shmid,NULL,0);

	//1-1.打开信号登,设置初值 4
	
	 sem_t *mySem;
	 mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,5);
	 if(NULL==mySem)
	{
			perror("sem_open error");
	}
	



	while(1){

		sleep(2);
		//1-2.获得当前信号量的值
		int sem_v;
		sem_getvalue(mySem,&sem_v);
		//printf("sem_v=%d\n",sem_v);

		if(sem_v==4){
			//1-3.将信号量的值减1
			sem_wait(mySem);
			printf("p2:%s\n",pShm);
			//4.读写
			memset(pShm,'\0',1024);
			strcpy(pShm,"择菜");
		}
	}
	//5.分离共享内存
	shmdt(pShm);
	//6.删除共享内存
	shmctl(shmid,IPC_CREAT,NULL);
	return 0;
}

#include <stdio.h>
#include "shm.h"
#include <string.h>
int main(void)
{
	//1.通过ftok获得key
	//2.创建共享内存 shmget
	//3.将共享内存映射到具体的进程空间  shmat
	//4.读写
	//5.分离共享内存
	//6.删除共享内存
	//1.通过ftok获得key
	key_t key=0;
	key=ftok("./",12);
	if(key<0)
	{
		perror("ftok error");
		return -1;
	}
	//2.创建共享内存 shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);
	if(shmid<0)
	{
		perror("shmget error");
		return -1;
	}




	//3.将共享内存映射到具体的进程空间  shmat
	char * pShm=NULL;
	pShm=shmat(shmid,NULL,0);

	//1-1.打开信号登,设置初值 4
	
	 sem_t *mySem;
	 mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,5);
	 if(NULL==mySem)
	{
			perror("sem_open error");
	}
	



	while(1){
		sleep(3);	
		//1-2.获得当前信号量的值
		int sem_v;
		sem_getvalue(mySem,&sem_v);
	//	printf("sem_v=%d\n",sem_v);

		if(sem_v==3){
			//1-3.将信号量的值减1
			sem_wait(mySem);
			printf("%s\n",pShm);
			//4.读写
			memset(pShm,'\0',1024);
			strcpy(pShm,"洗菜");
		}
	}
	//5.分离共享内存
	shmdt(pShm);
	//6.删除共享内存
	shmctl(shmid,IPC_CREAT,NULL);
	return 0;
}

#include <stdio.h>
#include "shm.h"
#include <string.h>
int main(void)
{
	//1.通过ftok获得key
	//2.创建共享内存 shmget
	//3.将共享内存映射到具体的进程空间  shmat
	//4.读写
	//5.分离共享内存
	//6.删除共享内存
	//1.通过ftok获得key
	key_t key=0;
	key=ftok("./",12);
	if(key<0)
	{
		perror("ftok error");
		return -1;
	}
	//2.创建共享内存 shmget
	int shmid=0;
	shmid=shmget(key,1024,IPC_CREAT|0666);
	if(shmid<0)
	{
		perror("shmget error");
		return -1;
	}




	//3.将共享内存映射到具体的进程空间  shmat
	char * pShm=NULL;
	pShm=shmat(shmid,NULL,0);

	//1-1.打开信号登,设置初值 4
	
	 sem_t *mySem;
	 mySem=sem_open("mySem",O_CREAT|O_RDWR,0664,5);
	 if(NULL==mySem)
	{
			perror("sem_open error");
	}
	



	while(1){
	
		sleep(3);
		//1-2.获得当前信号量的值
		int sem_v;
		sem_getvalue(mySem,&sem_v);
		//printf("sem_v=%d\n",sem_v);

		if(sem_v==2){
			//1-3.将信号量的值减1
			sem_wait(mySem);
			printf("%s\n",pShm);
			//4.读写
			memset(pShm,'\0',1024);
			strcpy(pShm,"切菜");
			sem_post(mySem);
			sem_post(mySem);
			sem_post(mySem);
			sem_post(mySem);
		}
	}
	//5.分离共享内存
	shmdt(pShm);
	//6.删除共享内存
	shmctl(shmid,IPC_CREAT,NULL);
	return 0;
}

补充
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值