Linux系统编程(11)——进程间通信-概念、匿名管道pipe、命名管道mkfifo

为什么要进行进程间通信?

进程之间具有独立性,每个进程都有自己的虚拟地址空间进程A不知道进程B的虚拟地址空间中的数据。这好比一个人不知道另一个人脑子中怎么想的一样。

介质?

进程间通信需要“介质”,两个进程都能访问到的公共资源。

借助文件就可以完成进程间通信,这是最简单,最常见手段。


操作系统专门提供的进程间通信方式:匿名管道    命名管道    消息队列    共享内存    信号量

工作中,最最最重要的进程间通信方式——网络

管道

内核中的一块内存(构成一个队列),使用一对文件描述符进行访问,读文件描述符就是队列中读数据,写文件描述符是队列中插入数据。


匿名管道:

#include <unistd.h>

功能:

创建一无名管道

原型:

int pipe(int fd[2])

参数:

fd:文件描述符数组,其中fd[0]表示读端, fd[1]表示写端。

返回值:

成功返回0,失败返回错误代码。

一个进程,pipe的演示:

#include<stdio.h>
#include<unistd.h>
#include<string.h>

//一个进程,pipe的演示
int main() {
	//使用pipe 函数创建一对文件描述符,通过这一对文件描述符,就可以操作内核中的管道
	int fd[2];
	int ret = pipe(fd); //peipe创造输出型数组,两个
	if (ret < 0) {
		perror("pipe");   //最常见失败方式,文件描述符用尽
		return 1;
	}


	//fd[0]  用于读数据
	//fd[1]  用于写数据

	char buf[1024] = "hehe";
	write(fd[1], buf, strlen(buf));

	char buf_output[1024] = { 0 };
	ssize_t n = read(fd[0], buf_output, sizeof(buf_output)-1);
	buf_output[n] = '\0';
	printf("%s\n", buf_output);


	//管道使用完成之后需要关闭描述符
	close(fd[0]);
	close(fd[1]);
}


//Makefile
test:test.c
	gcc $^ -o $@

进程间通信-管道:

代码演示:

#include<stdio.h>
#include<unistd.h>
#include<string.h>
int main() {
	//使用pipe 函数创建一对文件描述符,通过这一对文件描述符,就可以操作内核中的管道
	int fd[2];
	int ret = pipe(fd); //peipe创造输出型数组,两个
	if (ret < 0) {
		perror("pipe");   //最常见失败方式,文件描述符用尽
		return 1;
	}
	//fd[0]  用于读数据
	//fd[1]  用于写数据

	ret = fork(); //创建子进程
	if (ret>0) {
		//father
		//写数据
		char buf[1024] = "hehe";
		write(fd[1], buf, strlen(buf)); //给fd[1]写,写buf里面的,长度是strlen(buf)
	}
	else if (ret = 0) {
		//child
		//读数据
		char buf_output[1024] = { 0 };
		ssize_t n = read(fd[0], buf_output, sizeof(buf_output)-1);
		buf_output[n] = '\0';
		printf("child read: %s\n", buf_output);
	}
	else {
		perror("fork");
	}

	//管道使用完成之后需要关闭描述符
	close(fd[0]);
	close(fd[1]);
}

//write 和 read  代码互换 就实现反功能

//Makefile
test:test.c
	gcc $^ -o $@

管道类似队列:写了就是入队列,读就是出队列,读了,管道中就没有因此,如果多个进程都读,但是它只能读到一个数据,谁先执行 read  读到数据,因为“同步互斥机制”不会读到一人一半数据

注意:

1.多个进程读写管道,数据不会发生错乱   

2.如果管道为空,尝试读,就会在 read 阻塞。

3.如果管道满了,尝试写,就会在write 函数出阻塞


注:如果一个正在进行的进程堵塞了,利用  gdb attach pid<进程的pid>  就可以进行调试,在输入 bt  查看调用栈,就可以看阻塞到哪了。


匿名管道特点:

  • 只能用于具有共同祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。 
  • 流式工作,就是水管一样
  • 一般而言,进程退出,管道释放,所以管道的生命周期随进程
  • 一般而言,内核会对管道操作进行同步与互斥
  • 管道是半双工的。(一个进,一个出)

命名管道

命名实现:

mkfifo  filename<文件名>    这个文件名是:p 类型,即管道文件

代码实现:分成两个文件writer.c  和 reader.c


//先执行	myfifo myfifo  命令,创建管道文件 myfifo

//vim   reader.c 文件中
#include<stdio.h>
#include<unistd.h>
#include<string.h>

int main() {
	//对命名管道操作和文件操作一摸一样
	int fd = open("./myfifo", O_RDONLY);  //只读打开管道文件
	if (fd < 0) {
		perror("reader open");
		return 1;
	}
	while (1)  //开始读
	{
		char buf[1024] = { 0 };
		sszie_t n = read(fd, buf, sizeof(buf));
		if (n < 0) {
			perror("read");
			return 1;
		}
		if (n == 0) {  //写端写完,读端读完
			printf("read over\n");
			return 0;
		}
		buf[n] = '/0';
		printf("[read] %s\n", buf);
	}

	close(fd);
}

//vim 编辑小技巧:
//打开多个标签页:  :tabe  filename<文件名>
//切换标签页: gt到下一个标签页  gT到上一个标签页  :q  关闭当前标签页   :qa   全部关闭
//f [字符]  行内移动到指定字符
//某个字符打错了,按 s,输入字符就好了
//快速调整连个相邻字符,光标放在前一个字符,然后按:x  p
//vim   writer.c 文件中
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
int main() {
	//对命名管道操作和文件操作一摸一样
	int fd = open("./myfifo", O_RDONLY);  //只读打开管道文件
	if (fd < 0) {
		perror("reader open");
		return 1;
	}
	while (1)   //开始写
	{
		printf("->");  //给用户写提示
		fflush(stdout);
		char buf[1024] = { 0 };
		//让用户输入一个字符串让后再写
		read(0, buf, sizeof(buf)-1);   //stdin  文件标识符 0
		sszie_t n = write(fd, buf, strlen(buf));
	}

	close(fd);
}

Makefile文件:

//Makefile

.PHONY:all
all : reader writer   //一个make生成所有的


reader : reader.c
    gcc $^ -o $@

writer : writer.c
    gcc $^ -o $@

.PHONY:clean
clean :
    rm reader writer

当然,是两个文件,很麻烦,只是演示这个过程的实现,明白原理,熟练一下open,write 操作。

命名管道特点:除了匿名管道的第一个亲缘关系,其他都是。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值