阅读了《Unix/Linux系统编程》,并查了一些资料,对fork wait exec等系统调用进行了总结。
新人一枚,有错误的话请批评指正!
参考资料
1. 一些Unix/Linux进程相关词汇
-
进程上下文:
进程的上下文就是外界给进程提供的运行环境,即程序正确运行所需的状态组合。当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称为该进程的上下文。
-
上下文切换:
不同任务(进程)之间的执行切换机制称为上下文切换,将一个任务的执行环境更改为另一个任务的执行环境。
-
并发:
逻辑上的同时进行。如果上下文切换的够快,就会给人一种同时执行多个任务的错觉。这种逻辑并行性称为并发。
-
并行:
物理上的同时进行(真正的同时进行)。对于多CPU或处理器内核的多处理器系统中,可在不同CPU上实时、并行的执行多项任务。
-
执行映像:
包含代码、数据和堆栈的存储区。程序和进程之间不存在一一对应的关系,一个程序可以对应多个的进程。程序是静态的,存储在计算机磁盘中,进程是动态的,存在生命周期,有“生老病死”。我们通常把进程看作为是程序在内存中的镜像image。
-
进程:
进程是对映像的执行(也可以理解为一个执行中程序的实例)。每个进程用一个独特的数据结构表示,即为进程控制块(PCB),PCB保存着该进程的所有信息。
2. Linux中进程相关系统调用
2.1 fork()系统调用
用法:
#include<unistd.h>
#include<sys/types.h>
int pid = fork();
百度百科定义:复刻(英语:fork
,又译作派生、分支)是UNIX或类UNIX中的分叉函数,fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。
fork()
创建子进程并返回子进程的pid
(进程识别号),如果失败返回-1
。父进程调用fork()
系统调用后陷入内核态,并创建拥有自己的内核态堆栈和用户态映像的子进程。创建的子进程拥有与父进程完全相同的用户态映像,因此可以认为子进程就是父进程的一个复刻(因此连执行到哪一行都一样)。
并且,允许子进程继承父进程打开的所有文件。因此,父进程和子进程都可以从同一个stdin
标准输入文件获得输入,并输出到同一个stdout
标准输出文件、stderr
标准错误文件(可以理解为从同一个终端获取输入与显示输出)。
在创建完子进程即fork()
函数执行完后,parent父进程获得子进程pid
号作为返回值,而刚创建的子进程会返回到相同的语句,获得的返回值为0。
示例:父进程创建子进程后,两个进程打印fork()函数返回值并显示在相同终端上
main.c
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main(){
printf("test begin\n");
int pid = fork();
if(pid){
//父进程执行此部分
printf("this is parent process : return value = %d\n",pid);
}
else{
//子进程执行此部分
printf("this is child process : return value = %d\n",pid);
}
}
运行结果:
xtark@xtark-vmpc:~/桌面/linux_study/section3$ gcc main.c
xtark@xtark-vmpc:~/桌面/linux_study/section3$ ./a.out
test begin
this is parent process : return value = 3360
this is child process : return value = 0
可见父进程成功创建子进程并获得返回值3360(子进程pid),而子进程获得的fork()函数返回值为0。并且"test begin"只被打印了一次,因此说明fork函数将运行着的程序分成2个(几乎)完全一样的进程,连执行到哪一行都一样。父子进程能够将字符串输出到同一终端,说明子进程继承了父进程打开的所有文件。
2.2 getpid()和getppid()系统调用
这两个系统调用很简单,getpid()
系统调用返回调用进程的pid,getppid()
系统调用返回父进程的pid(ppid即为parent pid)。
示例:父进程创建子进程后,父进程打印自己与子进程pid;子进程打印自己