提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
-
- [2.10 进程间通信简介(IPC iner process communication)](#2.10 进程间通信简介(IPC iner process communication))
- 2.11匿名管道概述
- 2.12父子进程通过匿名管道通信
2.10 进程间通信简介(IPC iner process communication)
简称:
GUI:图形用户 接口 graphic user interface
IDE:集成开发环境
API:应用程序接口
同步和异步
看医生一个一个去,异步是好几个人一起。
异步容易产生安全问题。
Linux进程间通信的方式(记)
还有一种:内存映射
在讨论Unix进程和System V进程之间的区别之前,有必要先了解一下这两个术语的含义。
Unix 是一种广泛使用的操作系统,它有很多不同的变体或分支,例如Linux,BSD,Solaris等。这些变体基于原始的Unix系统,并添加或修改了一些特性。Unix进程是在这些系统中运行的程序实例。
System V(读作"System Five")是UNIX的一个主要版本,由AT&T贝尔实验室在20世纪80年代开发。这个版本的UNIX对UNIX的历史发展产生了深远影响,并为许多现代UNIX和类UNIX系统,包括Linux,设置了很多标准。
所以,我们在讨论Unix进程和System V进程之间的区别时,实际上是在讨论不同Unix变体或版本之间进程管理的差异。
有些进程管理的特性在System V中是独有的,比如它引入了更强大的进程间通信(IPC)机制,包括信号量,消息队列和共享内存。另一方面,许多现代的Unix系统(包括Linux和BSD)也实现了自己的IPC机制和其他进程管理特性,有些可能与System V的实现有所不同。
同时,Unix进程和System V进程的行为也可能受到具体操作系统内核的调度策略、资源管理策略等因素的影响,这些因素都可能导致在不同系统或版本上的进程表现出不同的行为。
总的来说,尽管存在这些差异,但是Unix进程和System V进程的基本概念和设计原则是相同的。这是因为所有的Unix和类Unix系统都继承了原始Unix的设计理念,包括进程的概念,进程的生命周期管理,以及进程间的通信等。
2.11匿名管道概述
匿名管道
每个进程的内核有文件描述符表,其中0 1 2分别代表标准输入、标准输出、标准错误。标准输入输出的文件就是输出,是从内存角度来看的。输出就是从内存输出到文件(写)。管道即改变了两个进程的输出和输入对象
解释:
- ls获取一个目录中文件的列表,"|"创建管道服务,wc统计文件数目。
ls
是一个列出目录内容的命令。当不带任何参数运行时,ls
会列出当前目录下的所有文件和目录。|
是一个管道操作符,它可以把一个命令的输出作为另一个命令的输入。ls | wc -l
就是把ls
的输出(即目录的内容列表)作为wc -l
的输入。wc
是"word count"的缩写,它是一个统计文本文件中字节数、单词数和行数的命令。当带上-l
参数时,wc -l
只统计输入中的行数。- 因此,
ls | wc -l
这个命令组合的作用是:列出当前目录下的所有文件和目录,并计算它们的数量。 wc
是 Linux 和 Unix 系统中的一个命令,它代表 "word count",即"字数统计"。这个命令可以用来计算文本文件中的字节数、单词数和行数。
关于wc命令:
wc
命令的基本使用格式是 wc [选项] 文件名
。你可以指定一个或多个文件名,wc
会为每个文件单独计算这些统计量,并在最后一行给出所有文件的总计。
wc
命令的主要选项包括:
-l
:仅计算行数-w
:仅计算单词数-c
:仅计算字节数-m
:仅计算字符数
例如,wc -l file.txt
就会计算出 file.txt
文件中的行数。如果你不指定任何选项,wc
会同时计算行数、单词数和字节数,并按照这个顺序输出结果。
请注意,wc
命令的 "字" 和 "单词" 的定义可能与你的直觉有所不同。在 wc
的上下文中,一个 "字" 是指一个字节,而一个 "单词" 是指由空白字符(如空格、制表符或换行符)分隔的字符串。因此,如果你的文件中包含非ASCII字符(如UTF-8编码的中文字符),wc -c
和 wc -m
的结果可能会不同,因为一个非ASCII字符可能由多个字节组成。
管道的特点(记)
管道两端对应文件描述符
从现实应用角度理解单工、双工、半双工:
单工-遥控器发送数据给电视(单向发送消息)
双工-打电话
半双工-同一时刻,数据只能往一个方向发送,比如对讲机(双向发送 但不同时)
为什么可以使用管道进行进程间通信
fork()创建子进程,父子进程共享文件描述符fd,文件描述符表处于内核中,上图中5指向管道读端,6指向管道写端。
管道的数据结构
环形队列(循环队列)逻辑上,可覆盖被读走数据的内存写入数据
展开成一个长条,可以看成读指针总是跟在写指针屁股后面
匿名管道的使用
2.12父子进程通过匿名管道通信
创建匿名管道
管道默认是阻塞的:如果管道中没有数据,read阻塞,如果管道满了,write阻塞
cpp
/*
#include <unistd.h>
int pipe(int pipefd[2]);
功能:创建一个匿名管道,用来进程间通信。
参数:int pipefd[2] 这个数组是一个传出参数。
pipefd[0] 对应的是管道的读端
pipefd[1] 对应的是管道的写端
返回值:
成功 0
失败 -1
管道默认是阻塞的:如果管道中没有数据,read阻塞,如果管道满了,write阻塞
注意:匿名管道只能用于具有关系的进程之间的通信(父子进程,兄弟进程)
*/
// 子进程发送数据给父进程,父进程读取到数据输出
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// 重点:在fork之前创建管道
int pipefd[2];//传出参数
int ret = pipe(pipefd);
if(ret == -1) {
perror("pipe");
exit(0);
}
// 创建子进程
pid_t pid = fork();
if(pid > 0) {
// 父进程:可实现先读再写
printf("i am parent process, pid : %d\n", getpid());
// 关闭写端
//close(pipefd[1]);
// 从管道的读取端读取数据
char buf[1024] = {0};
while(1) {
int len = read(pipefd[0], buf, sizeof(buf));
printf("parent recv : %s, pid : %d\n", buf, getpid());
//向管道中写入数据
char * str = "hello,i am parent";
write(pipefd[1], str, strlen(str));
sleep(1);
}
} else if(pid == 0){
// 子进程:可实现先写再读
printf("i am child process, pid : %d\n", getpid());
// 关闭读端
//close(pipefd[0]);
char buf[1024] = {0};
while(1) {//while循环实现不断的发送数据
// 向管道中写入数据
char * str = "hello,i am child";
write(pipefd[1], str, strlen(str));
sleep(1);
//父子进程交替接收数据
int len = read(pipefd[0], buf, sizeof(buf));
printf("child recv : %s, pid : %d\n", buf, getpid());
bzero(buf, 1024);
}
}
return 0;
}
//一个管道如果用作双向的数据传递,就容易出现父进程发送父进程接收的问题,
//所以一般父子进程的输入和输出的规定好的,不再交换。可以在一开始就关掉一个fd
查看管道缓冲大小函数
用ulimit -a命令查看 上图表示缓冲区有8块,每一块是512字节,所以一共是8*512 = 4K大小
cpp
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int pipefd[2];//传出参数
int ret = pipe(pipefd);
// 获取管道的大小:4KB 4096 可修改
//第二个参数为宏值,表示获取管道的大小
long size = fpathconf(pipefd[0], _PC_PIPE_BUF);
printf("pipe size : %ld\n", size);
return 0;
}