文章目录
创建进程的方法
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);
system
system系统调用可以启动一个新的进程,但是父进程会挂起,等待新的进程结束。
进程间通信方法
管道(Pipe)
管道的种类
- 无名管道(通常就叫管道) Pipe
- 命名管道 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的消息只能传递消息本身,让接收端对不同消息产生不同处理。
Linux消息队列
消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
来源:https://segmentfault.com/a/1190000010739303
Linux中提供了不同进程中发送数据块的方法,就是消息队列。
消息队列的好处是,消息队列由系统运行,发送端和接收端不需要考虑消息的同步问题,只需要接收和发送就好了。
- 消息队列是异步的。发送者和接收者不需要同时在线,它们可以独立地工作。这种方式提供了一种高效的通讯方式,特别是在高并发的环境中。
- 当队列满时,发送者进程可能会被阻塞,直到队列中有足够的空间为止。
- 消息队列的大小、每个消息的大小和消息队列的总大小都是由限制的。
参考:
Linux进程间通讯方式的深入对比与分析和权衡 - 泡沫o0的文章 - 知乎
【Linux】进程间通信(IPC)之消息队列详解及测试用例
信号
信号比较麻烦,我也没用过,直接参考以下文章:
参考:
C++项目实战-信号
信号集(未决信号集,阻塞信号集)
Socket
通过本地Socket来进行IPC,本地Sockset和通常的网络Socket设置有点不同,参考以下文章。
参考:
Linux进程间通信方式–本地socket