- 1. 创建进程
- 2. exec函数族
- 2.1 execlp
- 2.2 execl
- 3. 回收子进程
- 3.1 wait函数
- 3.2 waitpid函数
- 4. 进程间通信(IPC)
- 4.1 管道(PIPE)
- 4.2 有名管道(FIFO)
- 4.3 共享映射区(共享内存)
- 4.4 本地套接字
c/c++中,使用fork()函数创建一个进程。
pid_t pid = fork();
子进程自fork()以后开始执行。
fork()函数返回值,为pid_t类型,父子进程依靠pid的不同进行区分。如果fork失败,pid为-1;如果fork成功的话,对于父进程来说,pid是一个正整数,对于子进程来说,pid为0。
子进程创建后,为了节省资源,父子进程之间的共享,遵循读时共享,写时复制的原则。
父子进程共享:1. 文件描述符。 2. mmap建立的映射区。注意,程序中的全局变量什么的,都是独立的,不共享。
fork以后,父进程先执行还是子进程先执行,取决于内核所使用的进程调度算法
2. exec函数族进程当中去执行另外的程序可以使用exec函数族。
当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行,调用exec并不会创建新的进程,所以调用exec前后该进程的id并未改变。
2.1 execlp 2.2 execl 3. 回收子进程孤儿进程:父进程比子进程先结束,则该子进程为孤儿进程。此时,子进程的父进程成为init进程,称为init进程领养孤儿进程。但是,实际测试发现,在ubuntu16.04环境下,不是被init进程领养,而是被/sbin/upstart进程领养
僵尸进程:子进程进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸进程。
使用kill命令无法终止僵尸进程,因为kill命令只能用来终止进程,而僵尸进程已经终止了。
#include#include pid_t waitpid(pid_t pid, int *status, int options);
- 阻塞等待子进程退出
- 回收子进程残留资源
- 获取子进程结束状态(退出原因)
一个wait函数只能回收一个子进程,如果有多少子进程的话,谁先结束,就回收谁。
3.2 waitpid函数#include#include pid_t waitpid(pid_t pid, int *status, int options);
功能上包含了wait函数。
4. 进程间通信(IPC)- 管道(使用最简单)
- 信号(开销最小)
- 共享映射区(也叫共享内存)(无血缘关系)
- 本地套接字(最稳定)
-
管道是一个伪文件,是内核中的一块缓冲区(默认4k,可以通过ulimit -a查看)。
-
管道一端读,一端写。
-
管道是半双工通信(单向交替传输)。
-
管道中的数据,读出了就没了,管道不进行保存,也就是说不能反复读取。
-
管道只能在有血缘关系的进程间使用。
关键函数是pipe()
#include4.2 有名管道(FIFO) 4.3 共享映射区(共享内存)int pipe(int pipefd[2]); // fd[0] 读端。 // fd[1] 写端。
#includevoid *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
有血缘关系的进程间通信,测试代码:
#include#include #include #include #include #include #include #include #include #include #include using std::cout; using std::cin; using std::endl; int var = 100; int main(int argc, char const *argv[]) { int *p; int len = 4; // 建立映射区的大小 p = (int *)mmap(nullptr, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if(p == MAP_FAILED){ // 注意 不是 p == -1 cout << "mmap error" << endl; return -1; } pid_t pid = fork(); if(pid == 0){ *p = 2000; var = 1000; printf("child,*p = %d, var = %dn", *p, var); }else{ // 父进程 sleep(1); printf("parent,*p = %d, var = %dn", *p, var); // 这里的var输出100,因为父子进程间不共享全局变量 wait(nullptr); int ret = munmap(p, len); if(ret == -1){ cout << "munmap error" << endl; return -1; } } return 0; }
- MAP_SHARED 共享映射,父子进程共享映射区。
- MAP_PRIVATE 私有映射,父子进程各自独占映射区。



