所有正在运行的程序都有唯一的进程ID.的 进程ID,一个非负整数,是一个过程,是唯一的标识符 总是唯一的.但是,可以重用进程ID.
当进程终止时,其ID可以重用.某些系统会延迟重用,以便新创建的进程不会与旧进程混淆.
某些ID是"保留"的,因为系统进程正在使用它们,例如调度程序进程.另一个示例是始终占用PID 1 的init进程.根据系统,可能会主动保留ID.
运行命令
> ps -eaf | head -n 5
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 11:49 ? 00:00:02 /sbin/init splash
root 2 0 0 11:49 ? 00:00:00 [kthreadd]
root 3 2 0 11:49 ? 00:00:00 [ksoftirqd/0]
root 5 2 0 11:49 ? 00:00:00 [kworker/0:0H]
Run Code Online (Sandbox Code Playgroud)
和
> pidof init
1
Run Code Online (Sandbox Code Playgroud)
将允许您独立验证这一点.1
在C中,我们可以使用以下函数来获取调用进程的进程ID和调用进程的父进程ID,
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
Run Code Online (Sandbox Code Playgroud)
流程可以创建其他流程.创建的进程称为" 子进程 ",我们将创建它们的进程称为" 父进程 ".
要创建子进程,我们使用系统调用
fork()
#include <unistd.h>
pid_t fork(void);
Run Code Online (Sandbox Code Playgroud)
该函数由父进程调用一次,但它返回两次.子进程中的返回值为0,父进程中的返回值是新子进程的进程ID.1
进程可以有多个子进程,但是没有系统调用进程来获取其所有子进程的进程ID,因此父进程会观察子进程的返回值,并可以使用这些标识符来管理它们.
一个进程只能有一个父进程,它总是可以通过调用获得getppid.
孩子是复制父的,它得到一个复制母公司的数据空间,堆和栈的.他们不共享这些内存部分!2
我们将编译并执行以下代码片段以查看其工作原理,
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
int main(void) {
int var = 42; // This variable is created on the stack
pid_t pid;
// Two processes are created here
// v~~~~~~~~~~|
if ((pid = fork()) < 0) {
perror("Fork failed");
} else if (pid == 0) { // <- Both processes continue executing here
// This variable gets copied
var++;
printf("This is the child process:\n"
"\t my pid=%d\n"
"\t parent pid=%d\n"
"\t var=%d\n", getpid(), getppid(), var);
} else {
printf("This is the parent process:\n"
"\t my pid=%d\n"
"\t child pid=%d\n"
"\t var=%d\n", getpid(), pid, var);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我们将在执行程序时看到,无法保证首先执行哪个进程.它们甚至可以同时操作,有效地交错输出.3
$ # Standard compilation
$ gcc -std=c99 -Wall fork_example1.c -o fork_example1
$ # Sometimes the child executes in its entirety first
$ ./fork_example1
This is the child process:
my pid=26485
parent pid=26484
var=43
This is the parent process:
my pid=26484
child pid=26485
var=42
$ # and sometimes the parent executes in its entirety first
$ ./fork_example1
This is the parent process:
my pid=26461
child pid=26462
var=42
This is the child process:
my pid=26462
parent pid=26461
var=43
$ # At times the two might interleave
$ ./fork_example1
This is the parent process:
my pid=26455
This is the child process:
my pid=26456
parent pid=26455
var=43
child pid=26456
var=42
Run Code Online (Sandbox Code Playgroud)
1 PID代表进程ID,PPID代表 父进程ID.
2进程ID 0保留供内核使用,因此0不可能是子进程ID.
3许多系统不执行这些内存段的完整副本,而只是在任一进程执行写操作时才创建副本.最初,共享区域被内核标记为"只读",并且每当进程尝试修改这些区域时,内核都会授予每个进程自己的内存副本.
4标准输出被缓冲,因此它不是一个完美的例子.