到目前為止,我們知道每當(dāng)執(zhí)行一個(gè)程序時(shí),就會(huì)創(chuàng)建一個(gè)進(jìn)程,并在執(zhí)行完成后終止。 如果我們需要在程序中創(chuàng)建一個(gè)進(jìn)程,并且可能希望為其安排不同的任務(wù)。 這可以實(shí)現(xiàn)嗎? 是的,顯然是通過進(jìn)程創(chuàng)建來實(shí)現(xiàn)。 當(dāng)然,工作完成后進(jìn)程會(huì)自動(dòng)終止,或者根據(jù)需要終止。
過程創(chuàng)建是通過fork()系統(tǒng)調(diào)用實(shí)現(xiàn)的。 新創(chuàng)建的進(jìn)程稱為子進(jìn)程,啟動(dòng)該進(jìn)程的進(jìn)程(或執(zhí)行開始時(shí)的進(jìn)程)稱為父進(jìn)程。 在fork()系統(tǒng)調(diào)用之后,現(xiàn)在有兩個(gè)進(jìn)程 - 父進(jìn)程和子進(jìn)程。 如何區(qū)分它們? 非常簡(jiǎn)單,可通過它們的返回值來區(qū)分它們。
在創(chuàng)建子進(jìn)程之后,讓我們看看fork()系統(tǒng)調(diào)用細(xì)節(jié)。參考以下代碼 -
#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);
創(chuàng)建子進(jìn)程。 這個(gè)調(diào)用之后,有兩個(gè)進(jìn)程,現(xiàn)有的進(jìn)程稱為父進(jìn)程,新創(chuàng)建的進(jìn)程稱為子進(jìn)程。
fork()系統(tǒng)調(diào)用返回三個(gè)值之一 -
讓我們來看看一個(gè)簡(jiǎn)單的程序。
// 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;
}
編譯 -
yiibai$ gcc basicfork.c -o basicfork
執(zhí)行后輸出結(jié)果如下 -
Called fork() system call
Called fork() system call
注 - 通常在調(diào)用
fork()之后,子進(jìn)程和父進(jìn)程將執(zhí)行不同的任務(wù)。 如果需要運(yùn)行相同的任務(wù),那么對(duì)于每個(gè)fork()調(diào)用,它將運(yùn)行n次,其中n是調(diào)用fork()的次數(shù)。
在上面的情況下,fork()被調(diào)用一次,因此輸出打印兩次(2次冪)。 如果fork()被調(diào)用3次,那么輸出將被打印8次(2的3次方)。 如果被稱為5次,則打印32次,依此類推。
看到fork()創(chuàng)建子進(jìn)程,就可以看到父進(jìn)程和子進(jìn)程的詳細(xì)信息了。
文件: 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;
}
編譯和執(zhí)行步驟 -
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
一個(gè)進(jìn)程可以以兩種方式之一終止 -
_exit()系統(tǒng)調(diào)用(或_Exit()系統(tǒng)調(diào)用)或exit()庫函數(shù)。_exit()和exit()之間的區(qū)別主要是清理活動(dòng)。 exit()在將控制權(quán)返回給內(nèi)核之前做了一些清理,而_exit()(或_Exit())會(huì)立即將控制權(quán)返回給內(nèi)核。
考慮下面的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);
}
編譯和執(zhí)行結(jié)果 -
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);
}
編譯和執(zhí)行結(jié)果 -
Hello, World!