方一凡和磊儿做家教的网站,网站诊断书,网站不备案有什么后果,培训心得体会目录 进程间通信
什么是进程间通信
进程间通信的一般规律
前言#xff1a;
管道
代码预准备#xff1a;
如何创建管道 -- pipe 函数
参数#xff1a;
返回值#xff1a;
wait 函数
参数#xff1a;
验证管道的运行#xff1a;
源文件 test.c #xff1a;
m…目录 进程间通信
什么是进程间通信
进程间通信的一般规律
前言
管道
代码预准备
如何创建管道 -- pipe 函数
参数
返回值
wait 函数
参数
验证管道的运行
源文件 test.c
makefile 文件 运行结果 进程间通信
什么是进程间通信 进程间通信Inter-Process Communication, IPC是操作系统中非常重要的一个概念它指的是不同进程之间进行数据交换或者传递消息的机制。 进程间通信的主要原因和目的是 资源共享不同的进程可能需要访问相同的资源或数据例如文件、数据库等。通过IPC可以实现对这些共享资源的有效管理和同步访问。 任务协作在很多情况下一个复杂的任务可能被分解为多个子任务由不同的进程来执行。为了完成整个任务这些进程之间需要相互通信以协调它们的工作流程。 提高效率对于一些计算密集型的任务可以通过将工作分配给多个进程来并行处理从而加速任务的完成。这时就需要有效的通信机制来保证各部分工作的正确性与一致性。 模块化设计软件开发时采用模块化的设计思想即将程序划分为相对独立但又能相互作用的功能单元即进程。这样做不仅有利于维护而且也使得系统更加灵活可扩展。良好的IPC支持能够促进这种架构模式的应用。 跨网络服务调用随着分布式系统的普及在不同主机上的进程也需要能够互相通信。这涉及到更高级别的IPC形式如RPC (Remote Procedure Call) 等技术。 进程间通信的一般规律 让不同的进程看到同一份资源 前言
假设现在有A、B进程在A进程中开辟一块空间并写入数据让 B 进程去 A 进程的这块空间读取数据虽然确实让不同的进程看到了同一份资源但是破坏了进程的独立性。 所以进程间通信需要有交换数据的空间且这块空间不能由通信双方任何一个提供那么这块空间只能由操作系统提供。 我们回顾一下父子进程假设父进程对同一个文件分别用读方式和写方式打开父进程将会得到两个文件描述符对象。
为什么对同一个文件分别用读方式打开和写方式打开会创建两个文件描述符对象?
当你使用读取模式例如 open(file.txt, r)和写入模式例如 open(file.txt, w)分别打开同一个文件时操作系统会为每次打开操作分配一个独立的文件描述符。这样做有几个原因 独立性每个文件描述符代表了对文件的一个独立访问路径。这意味着你可以同时从一个文件描述符读取数据而从另一个文件描述符写入数据即使它们指向的是同一个物理文件。这种独立性允许更灵活地处理文件。 位置指针每个文件描述符都有自己的文件偏移量或位置指针。当你通过不同的文件描述符读写文件时每个描述符的位置指针可以独立移动。这样在进行多线程或多进程操作时各个进程/线程可以安全地在不同位置上工作而不互相干扰。 权限控制以不同模式打开文件提供了对文件的不同级别的访问权限。比如只读模式下你只能读取文件内容而在写入模式下还可以修改文件。拥有两个文件描述符意味着可以根据需要选择适当的访问级别同时也增加了安全性因为不需要给所有操作都赋予完全相同的权限。 性能与资源管理尽管是同一份文件但根据具体的操作需求如顺序读取、随机写入等操作系统可能采取不同的策略来优化I/O性能。此外维护多个文件描述符也便于系统更好地跟踪哪些程序正在使用该文件并且有助于实现诸如引用计数这样的机制从而有效地管理文件相关的系统资源。 总之虽然这两个文件描述符对应于同一物理文件但是它们各自保持了自己的状态信息这使得在同一时间内能够执行更加复杂的并发操作同时也增强了系统的灵活性和安全性。
父进程得到两个文件描述符对象之后我们创建子进程子进程继承父进程的文件描述符表父子进程指向同一个文件和缓冲区这也就实现了父子进程看到同一份资源就可以实现进程间通信 管道 从前言中就可以看出管道的本质是文件 在 Linux 中管道pipe是一种进程间通信IPC, Inter-Process Communication的机制它允许一个进程的输出直接作为另一个进程的输入。
管道可以看作是连接两个或多个命令的数据流通道它使得数据可以在不同的程序之间流动而不需要通过临时文件。 标准的管道是单向的即数据只能从写端流向读端。 匿名管道
在前言中父进程和子进程的文件的读端和写端都是打开的为了符合管道是单向的我们可以选择让 父进程作为写端子进程作为读端 或者 父进程作为读端、子进程作为写端
如下图我们让父进程作为写端子进程作为读端 代码预准备
如何创建管道 -- pipe 函数
#include unistd.hint pipe(int pipefd[2]);
该函数用于创建一个匿名管道。
参数 pipefd这是一个指向两个整数的指针。pipe() 成功后这两个整数会被设置为新创建的管道的读端和写端的文件描述符。读端通常为 fd[0]写端通常为 fd[1]。 返回值 它在成功时返回 0并且通过其参数一个包含两个整数的数组来传递两个文件描述符如果调用失败pipe() 会返回-1并设置全局变量 errno 来指示具体的错误原因。 wait 函数
#include sys/types.h
#include sys/wait.hpid_t wait(int *status);
wait() 函数是 Unix 和 Linux 系统中用于进程控制的一个重要函数。它允许一个进程通常是父进程等待其子进程结束并获取子进程的退出状态。wait() 函数会阻塞调用者直到至少有一个子进程终止或接收到一个信号。
参数 status这是一个指向整数的指针用来存储子进程的退出状态信息。如果不需要这个信息可以传递 NULL。 返回值: 如果有子进程成功终止则返回该子进程的 PID如果没有子进程或者所有子进程都还在运行wait() 将一直阻塞直到至少有一个子进程终止。如果发生错误如被信号中断则返回-1并设置 errno。 验证管道的运行
源文件 test.c
#includestdio.h
#includestdlib.h
#includestring.h
#includeunistd.h
#includesys/types.h
#includesys/wait.hvoid writer(int wfd)
{const char *strhello father,I am child;char buffer[128];int cnt0;pid_t pidgetpid();//获得进程pidwhile(1){//向缓冲区里写入内容snprintf(buffer,sizeof(buffer),message:%s,pid:%d,count:%d\n,str,pid,cnt);//把缓冲区里的内容写入到管道write(wfd,buffer,sizeof(buffer));cnt;sleep(1);}
}void reader(int rfd)
{char buffer[128];while(1){//读取管道里的内容ssize_t nread(rfd,buffer,sizeof(buffer)-1);printf(father get a message: %s,buffer);}
}int main()
{int pipefd[2];int npipe(pipefd);if(n0){return 1;}printf(%d %d\n,pipefd[0],pipefd[1]);pid_t idfork();if(id0){//子进程创建成功//关闭读端close(pipefd[0]);writer(pipefd[1]);//写exit(0);}//父进程关闭写端close(pipefd[1]);reader(pipefd[0]);//读wait(NULL);return 0;
}
makefile 文件
testpipe:test.cgcc -o $ $^.PHONY:clean
clean:rm -f testpipe 运行结果
从下面的运行结果可以看出父进程接收到了子进程写的数据