[多进程] 进程间通信-笔记

本文介绍了在Linux和Windows中创建进程的不同方法,如fork、exec、system和CreateProcess,以及进程间通信的各种手段,包括管道、文件映射、共享内存、信号量、消息队列和Socket。重点讨论了它们的特点和应用场景。
摘要由CSDN通过智能技术生成

创建进程的方法

Linux

fork

使用fork()函数,可以创建子进程,子进程复制父进程的虚拟内存。和父进程共享代码。
fork()在父进程中返回子进程ID,在子进程中返回0,执行错误返回-1。
Linux c/c++之进程的创建

exec

exec函数簇,在子进程占用调用相关函数可以进行进程替换。
即从调用exec开始,子进程就替换成exec调用的进程,而原本的子进程代码将不再执行。

system

system系统调用可以启动一个新的进程,但是父进程会挂起,等待新的进程结束。

Windows

createprocess

windows中没有fork()。
windows中一般通过CreateProcess()函数调用一个执行的可执行程序,来启动一个新的进程,父进程不需要等待子进程结束。
看到网上有在windows中模拟fork()的方法,还没看过。
windows下创建进程,CreateProcess()详解及用法

shellexecute

shellexecute 可以启动一个新的进程,父进程不需要等待子进程结束。它支持文件关联,即不指定notepad, 直接让他打开一个txt文件,它也会用notepad(或者其他关联的程序)打开。
例如:

ShellExecuteA(NULL, "open", "D:\\text.txt", NULL, NULL, SW_SHOWNORMAL);

ShellExecute详细用法

system

system系统调用可以启动一个新的进程,但是父进程会挂起,等待新的进程结束。

进程间通信方法

管道(Pipe)

管道的种类

  1. 无名管道(通常就叫管道) Pipe
  2. 命名管道 FIFO-Pipe

特点

  • windows和linux都支持管道。
  • 无名管道用于父子进程之间。
  • 命名管道可以用于不相关的进程间的通信。
  • 管道是半双工的
  • 管道的可以设置阻塞和非阻塞

阻塞:
一个为只读而打开一个管道的进程会阻塞,直到另一个进程为只写打开管道
一个为只写而打开一个管道的进程会阻塞,直到另一个进程为只读打开管道
read()/write()也是阻塞的

非阻塞
以只读方式打开FIFO,如果没有进程为写而打开FIFO, 只读open成功,并且open不阻塞
以只写方式打开FIFO, 如果没有进程为读而打开FIFO,只写open将出错返回-1 (ENXIO: No Such device or address)
read()/write()也是阻塞的

无论是否阻塞,像一个读端关闭的管道写入数据会产生SIGPIPE错误

参考:
C++项目实战-多进程(一篇文章)
命名管道的阻塞和非阻塞模式的初步探讨

通过文件通信

可以通过新建一个文件,然后一个进程向里面写,一个进程从里面读。
其实这和管道思想类似。
参考:C++项目实战-多进程(一篇文章)

内存映射(文件映射)

内存映射就是通过内核把一个磁盘文件映射到进程的虚拟内存中。进程可以通过指针来访问映射的文件内存,对文件进行修改,内核会负责把修改同步回磁盘文件。

  • Windows和Linux都支持文件映射
  • 文件映射可以用于父子进程之间,也可以用于不相关进程,用于父子进程之间,只需要在fork()之前映射一次就行,因为子进程会拷贝父进程的虚拟内存;用于不相关进程之间,需要两个进程都进行映射。
  • 进行文件映射时,需要先打开文件,获取文件描述符,文件映射开始后,文件描述符随时可以close。
  • 如果用于进程间通信,必须设置文件映射为共享的,Linux选项是MAP_SHARED
  • 使用文件映射也存在谁读谁写的问题,它也不是全双工的

匿名映射

就是不指定文件描述符的映射,类似于管道和命名管道的区别,匿名映射只能用于父子进程之间。

参考:
C++项目实战-多进程(一篇文章)
[内存] windows 实现内存映射

共享内存 + 信号量(或者锁)

共享内存是一种进程间的通信机制,并且也是最底层的一种机制(其他的通信机制还有管道,消息队列等)。
进程之间通过访问一块共享的空间,来进行数据的通信(交换)。具体来讲,就是将一份物理内存映射到不同进程各自的虚拟地址空间,这样每个进程都可以读写这片相同的物理内存。
共享内存是速度最快的一种进程间通信(IPC)方式,它直接对内存进行存取,比操作系统提供的读写系统服务更快。
由上面的描述我们发现,当多个进程对同一片空间进行读写时必然会出现同步的问题,所以一般共享内存会和信号量或者锁机制一同使用,保证数据的一致性。

  • Windows和Linux都支持
  • Windows中共享内存和内存映射的调用API基本一样,都有CreateFileMapping()和MapViewOfFile(),根据下面参考文章,可以看出原理是差不多的,内存映射多了磁盘映射到物理内存这一步。
  • 参照内存映射,共享内存也可以用于父子进程或者非父子进程。
  • 共享内存是高效的进程间通信方法。

参考:
【学习笔记】windows 下的 shared memory(共享内存)原理与实践
C++项目实战-多进程(一篇文章)

消息队列

Windows消息队列

  • Windows中如果是窗口线程,是可以通过线程的消息队列进行IPC的,但是如果没有窗口线程,就没法用这个方法了,因为PostMessage函数需要窗口句柄。
  • Windows消息传递的参数是有限制的。(WParam和LParam都是32位整数)我感觉IPC中,Windows的消息只能传递消息本身,让接收端对不同消息产生不同处理。

进程间通信IPC-Windows消息

Linux消息队列

消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
来源:https://segmentfault.com/a/1190000010739303

Linux中提供了不同进程中发送数据块的方法,就是消息队列。
消息队列的好处是,消息队列由系统运行,发送端和接收端不需要考虑消息的同步问题,只需要接收和发送就好了。

  • 消息队列是异步的。发送者和接收者不需要同时在线,它们可以独立地工作。这种方式提供了一种高效的通讯方式,特别是在高并发的环境中。
  • 当队列满时,发送者进程可能会被阻塞,直到队列中有足够的空间为止。
  • 消息队列的大小、每个消息的大小和消息队列的总大小都是由限制的。

参考:
Linux进程间通讯方式的深入对比与分析和权衡 - 泡沫o0的文章 - 知乎
【Linux】进程间通信(IPC)之消息队列详解及测试用例

信号

信号比较麻烦,我也没用过,直接参考以下文章:

参考:
C++项目实战-信号
信号集(未决信号集,阻塞信号集)

Socket

通过本地Socket来进行IPC,本地Sockset和通常的网络Socket设置有点不同,参考以下文章。
参考:
Linux进程间通信方式–本地socket

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值