流程创建和终止(Process Creation & Termination)
到目前为止,我们知道无论何时执行程序,都会创建一个进程,并在执行完成后终止。 如果我们需要在程序中创建进程并且可能希望为其安排不同的任务,该怎么办? 这可以实现吗? 是的,显然是通过创建流程。 当然,在完成工作后,它会自动终止,或者您可以根据需要终止它。
通过fork() system call实现进程创建。 新创建的进程称为子进程,启动它的进程(或启动执行时的进程)称为父进程。 在fork()系统调用之后,现在我们有两个进程 - 父进程和子进程。 如何区分它们? 很简单,它是通过他们的返回值。
创建子进程后,让我们看一下fork()系统调用的详细信息。
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
创建子进程。 在此调用之后,有两个进程,现有的进程称为父进程,新创建的进程称为子进程。
fork()系统调用返回三个值中的任何一个 -
负值表示错误,即创建子进程失败。
为子进程返回零。
返回父进程的正值。 此值是新创建的子进程的进程ID。
让我们考虑一个简单的程序。
File name: basicfork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
fork();
printf("Called fork() system call\n");
return 0;
}
执行步骤 (Execution Steps)
编译 (Compilation)
gcc basicfork.c -o basicfork
Execution/Output
Called fork() system call
Called fork() system call
Note - 通常在fork()调用之后,子进程和父进程将执行不同的任务。 如果需要运行相同的任务,那么对于每个fork()调用,它将运行2次幂n次,其中n是fork()被调用的次数。
在上面的例子中,fork()被调用一次,因此输出被打印两次(2次幂1)。 如果调用fork(),比如说3次,则输出将被打印8次(2次幂3)。 如果它被调用5次,那么它会打印32次,依此类推。
看过fork()创建子进程后,就可以看到父进程和子进程的详细信息了。
文件名:pids_after_fork.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
pid_t pid, mypid, myppid;
pid = getpid();
printf("Before fork: Process id is %d\n", pid);
pid = fork();
if (pid < 0) {
perror("fork() failure\n");
return 1;
}
// Child process
if (pid == 0) {
printf("This is child process\n");
mypid = getpid();
myppid = getppid();
printf("Process id is %d and PPID is %d\n", mypid, myppid);
} else { // Parent process
sleep(2);
printf("This is parent process\n");
mypid = getpid();
myppid = getppid();
printf("Process id is %d and PPID is %d\n", mypid, myppid);
printf("Newly created process id or child pid is %d\n", pid);
}
return 0;
}
编译和执行步骤 (Compilation and Execution Steps)
Before fork: Process id is 166629
This is child process
Process id is 166630 and PPID is 166629
Before fork: Process id is 166629
This is parent process
Process id is 166629 and PPID is 166628
Newly created process id or child pid is 166630
一个过程可以以两种方式中的任何一种终止 -
异常地,在发送某些信号时发生,例如终止信号。
通常,使用_exit()系统调用(或_Exit()系统调用)或exit()库函数。
_exit()和exit()之间的区别主要是清理活动。 exit()在将控件返回给内核之前进行一些清理,而_exit() (或_Exit())会立即将控件返回给内核。
请考虑以下带exit()的示例程序。
文件名:atexit_sample.c
#include <stdio.h>
#include <stdlib.h>
void exitfunc() {
printf("Called cleanup function - exitfunc()\n");
return;
}
int main() {
atexit(exitfunc);
printf("Hello, World!\n");
exit (0);
}
编译和执行步骤 (Compilation and Execution Steps)
Hello, World!
Called cleanup function - exitfunc()
请考虑以下带有_exit()的示例程序。
文件名:at_exit_sample.c
#include <stdio.h>
#include <unistd.h>
void exitfunc() {
printf("Called cleanup function - exitfunc()\n");
return;
}
int main() {
atexit(exitfunc);
printf("Hello, World!\n");
_exit (0);
}
编译和执行步骤 (Compilation and Execution Steps)
Hello, World!