操作系统——进程间通信

进程间通信

	**管道**
	**共享内存**
	**消息队列**
	**信号量**

1.为什么需要进程间通信?
原因是由于进程都拥有自己独立的进程虚拟地址空间,从而导致了进程的独立性;通过进程间通信,可以让不同的进程进行协作。
2.目前最大的进程间通信的技术是:网络!

管道

1.从命令来看
ps aux | grep zpf ==》 " | " 就是管道
ps 和 grep 是命令,同时要理解也是一个程序
ps aux 的输出结果, 通过管道,传输给了 grep 程序。换一句话说,ps aux 的结果作为grep程序的输入
2. 管道就是在内核当中开辟的一块内存,也可以称之为内核的缓冲区
在这里插入图片描述
1.匿名管道
1.1 在内核当中创建出来的一块内存是没有标识符的!
1.2 如何去创建一个管道
int pipe (int fd[2]);
fd[2] : 整型参数,有两个元素, fd[0], fd[1]
fd 是一个出参数
输出型参数:参数在函数内部赋值,在函数外部使用
输入型参数:参数在函数内部使用
输入输出型参数: 参数在函数内部使用,在函数外部使用
fd 数组当中保存两个文件描述符
fd[0] : 读端, 读匿名管道的内存
fd[1] : 写端, 往匿名管道当中进行写
返回值: 成功返回0, 失败返回-1
在这里插入图片描述
1.管道是单双工通信,数据流向只能是从写端,流向读端
2.管道提供流式服务,好处:读端可以决定每次读多少个字节
3.管道的生命周期跟随进程

int fcntl(int fd, int cmd, … /* arg */);
int fd : 当前要操作的文件描述符的数值
int cmd : 告诉fcntl 函数, 接下来你做什么事情
F_GETFL (void) :获取文件描述符的属性信息
F_SETFL (int) : 设置文件描述符的属性信息
返回值:
当时F_GETFL的时候,返回的时文件描述符的属性信息
在这里插入图片描述
4.匿名管道只支持具有亲缘关系的进程进行进程间通信
先创建管道,再fork子进程

1.管道到底能够存储多大的数据:
pipe_size : 64K
pipe_buf : 4K
进程操作写端往匿名管道当中写的时候,如果写入的字节数量小于4k,则保证当前写入操作的原子性:
在这里插入图片描述
2.管道对应得读写端文件描述符设置成为非阻塞属性:
文件描述符的非阻塞属性: O_NONBLOCK
int flag = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flag | O_NONBLOCK)
文件描述符的属性是按照位图的方式来使用的
在这里插入图片描述
1.将写端文件描述符设置成为非阻塞属性fd[1], 读端文件描述符不管
1.1 读端文件描述符都关闭,调用write进程会收到管道破裂的信号SIGPIPE,导致当前的调用write的进程退出掉
1.2 读端文件描述符不关闭,但是也不读,写端一直写,直到将管道写满,则在调用write函数,会返回-1,报错:资源不可用
2. 将读端文件描述符设置成为非阻塞属性fd[0], 写端文件描述符不管
2.1 写端文件描述符关闭,读端一直读,直到将管道的内容读完,再次调用read函数,返回0,表示没有读到任何内容
2.2 写端文件描述符不关闭,但是也不写,读端调用读,则read函数会返回-1, 表示资源不可用
在这里插入图片描述
2.命名管道
1.命名管道也是在内核当中开辟的一段缓冲区,这段缓冲区是有标识符的;意味着,不同的进程,不需要有亲缘关系,只要通过标识符就能找到缓冲区
2.命名管道的创建
2.1 命令创建
mkfifo[命名管道文件]
prw-rw-r-- 1 zpf zpf 0 Nov 1 09:33 fifl
“p” : 代表的文件类型为管道文件
2.2 函数创建
mkfifo函数
3.特性
1.命名管道的生命周期也是跟随进程的
2.命名管道是具有标识符的
3.其他的特性和匿名管道是一致的

共享内存

在这里插入图片描述

  1. 在物理内存当中开辟了一段空间
  2. 这段为物理内存空间,可以被不同的进程附加到自己的共享区当中
  3. 附加的进程,通过操作共享区,来交换数据

char* lp - (char*)malloc(10)
lp --> [地址]
strcpy(lp, “linux-57”)

共享内存的接口
1.创建共享内存
int shmget(key_t key, size_t size, int shmflg);
key : 共享内存标识符, 这个标识符相当于共享内存的身份证
程序员在第一次创建的时候,可以随意给值,只要和当前操作系统当中的其它的
共享内存标识符不重复
eg.0x99999999 0x88888888 0x12345678
size : 共享内存的大小,单位字节
shmflg:
IPC_CREAT : 如果共享内存不存在,则创建共享内存
IPC_EXCL : 需要搭配IPC_CREAT一起使用,这样的宏在搭配使用的时候,还是采
用按位或的方式(其实核心的思想就是位图)
eg : IPC_CREAT | IPC_EXCL :
如果想要获取的共享内存,已经存在,则报错
如果想要获取的共享内存,是刚刚创建出来的共享内存,则返回操作句柄
总结:使用shmget这个函数的时候一定要自己刚刚创建出来的共享内存
返回值:返回值是返回共享内存的操作句柄
共享内存的标识符和共享内存的操作句柄区别是什么?
标识符:是用来标识共享内存的,相当于共享内存的身份证,意味着不同的进程可以通过标识符找到这个共享内存
操作句柄:进程可以通过操作句柄来对共享内存进行操作(附加,分离,删除)
ipcs命令看到的内容:
在这里插入图片描述
结论1:共享内存的生命周期是跟随操作系统内核的

2.将共享内存附加到进程

	void * shmat (int shmid, const void* shmaddr, int shmflg);

shmid:共享内存的操作句柄
shmaddr:附加到共享内存的生命虚拟地址,允许传递NULL值,让操作系统帮我们选择附加到共享区当中的哪那个地址,这个地址通过该函数的返回值返回给我们
shmflg:
SHM_RDONLY : 规定当前进程只能对共享存进行读操作
0 : 可读可写
返回值:返回共享内存附加到共享区的地址
结论2: 进程在读取共享内存的时候,是访问而不是拿走!

3.将共享内存和进程分离

int shmdt (const void* shmaddr);

shmaddr : shmat 的返回值

4.操作共享内存

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

shmid : 共享操作句柄
cmd : 告诉shmctl函数需要做什么操作
IPC_STAT : 获取当前共享内存的属性信息,放在buf当中,buf是出参
IPC_SET: 设置共享内存的属性信息,是用buf来进行设置的,buf是入参
IPC_RMID:删除共享内存,buf可以直接传递为NULL
buf:共享内存的结构体

5.删除共享内存
5.1 当使用shmctl或者使用ipcrm,删除共享内存之后,共享内存就实际被释放掉了
5.2 当共享内存被释放掉之后,共享内存的标识符会被设置成为0x00000000,表示其他进程不能通过之前的标识符找到该共享内存,并且共享内存的状态会被设置成为dest(destory)
5.2.1 当共享内存被释放掉之后,但是还是有进程在附加着共享内存,当前描述共享内
存的结构体并没有被释放,直到当前共享内存的附加进程数量为0的时候才会被释
放掉

//my_malloc()
	if(lp)
	{
		count++;
		return lp;
	}
	//malloc
	count++;
	return lp;
//my_free
	if(count > 0)
	{
		count--;
	}
	if (count <= 0)
	{
		free();
	}

消息队列

1.队列的特性是先进先出,消息对列也是满足先进先出的特性的,内核当中实现消息队列的时候,采用链表这个结构体
2.消息队列当中的元素是有类型的,每一种类型是有优先级概念的
在这里插入图片描述
同一类型保证先进先出特性

int msgget(key_t key, int msgflg);
int msgsnd(int msqid, const void* msgp, size_t msgsz, int msgflg);

msgflg:
IPC_NOWAIT : 非阻塞模式
0:阻塞模式

ssize_t magrcv(int maqid, void* msgp, size_t magsz, long msgtyp, int magflg);

long msgtype: 数据类型
== 0 : 取队列当中的第一个
> 0 : 取和msgtype相等的元素
< 0 : 先取绝对值,然后在范围内取最屌的优先级的元素

int msgctl(int msqid, int cmd, struct msqid_ds* buf);

结论:消息队列的生命周期也是跟随内核的

信号量

1.信号量的底层是一个计数器
2.型号量是用来进程控制的
在这里插入图片描述
临界资源:多个进程都能够访问到的资源,被称之为临界资源
多线程当中,多个线程都能访问到的资源被称之为临界资源
在这里插入图片描述
列举一下你所直到的进程间通信方式
管道,共享内存,消息队列,信号,网络,unix域套接字,信号量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值