博客專欄

EEPW首頁 > 博客 > 嵌入式Linux:創(chuàng)建進(jìn)程

嵌入式Linux:創(chuàng)建進(jìn)程

發(fā)布人:美男子玩編程 時(shí)間:2024-10-12 來源:工程師 發(fā)布文章

在 Linux 系統(tǒng)中,fork() 和 vfork() 是兩個(gè)常用的系統(tǒng)調(diào)用,用于創(chuàng)建新的進(jìn)程。



1


fork() 系統(tǒng)調(diào)用

函數(shù)原型如下:


#include <unistd.h>pid_t fork(void);


返回值:調(diào)用 fork() 的進(jìn)程(父進(jìn)程)會(huì)得到一個(gè)返回值。在父進(jìn)程中,fork() 返回子進(jìn)程的進(jìn)程 ID (PID);在子進(jìn)程中,fork() 返回 0;如果發(fā)生錯(cuò)誤,則返回 -1,并設(shè)置全局變量 errno。


1.1、工作機(jī)制

fork() 會(huì)創(chuàng)建一個(gè)新的進(jìn)程,這個(gè)進(jìn)程被稱為子進(jìn)程。子進(jìn)程幾乎是父進(jìn)程的完整副本,包括父進(jìn)程的代碼段、數(shù)據(jù)段、堆棧段和打開的文件描述符。子進(jìn)程和父進(jìn)程之間的唯一區(qū)別在于它們擁有不同的進(jìn)程 ID,并且 fork() 的返回值不同。


內(nèi)存空間:盡管子進(jìn)程復(fù)制了父進(jìn)程的內(nèi)存空間,但實(shí)際上,現(xiàn)代 Linux 系統(tǒng)使用了“寫時(shí)復(fù)制”(Copy-on-Write, CoW)技術(shù)。只有在父進(jìn)程或子進(jìn)程試圖修改內(nèi)存中的數(shù)據(jù)時(shí),內(nèi)核才會(huì)真正為子進(jìn)程分配新的內(nèi)存。這種機(jī)制極大地提高了 fork() 的效率,避免了不必要的內(nèi)存復(fù)制。


1.2、使用場(chǎng)景

fork() 適用于需要?jiǎng)?chuàng)建子進(jìn)程來執(zhí)行與父進(jìn)程不同任務(wù)的場(chǎng)景。它在網(wǎng)絡(luò)服務(wù)器、守護(hù)進(jìn)程和并行處理任務(wù)中被廣泛應(yīng)用。例如,網(wǎng)絡(luò)服務(wù)器可以使用 fork() 為每個(gè)客戶端請(qǐng)求創(chuàng)建一個(gè)新的子進(jìn)程,從而提高系統(tǒng)的并發(fā)性。


示例如下:


#include <stdio.h>#include <unistd.h>#include <sys/types.h> int main() {    pid_t pid = fork(); // 創(chuàng)建子進(jìn)程     if (pid < 0) {        // fork() 失敗        fprintf(stderr, "fork() 失敗n");        return 1;    } else if (pid == 0) {        // 子進(jìn)程        printf("這是子進(jìn)程, PID: %dn", getpid());    } else {        // 父進(jìn)程        printf("這是父進(jìn)程, 子進(jìn)程的 PID: %dn", pid);    }     return 0;}


在這個(gè)例子中,fork() 創(chuàng)建了一個(gè)新的子進(jìn)程。父進(jìn)程和子進(jìn)程會(huì)從 fork() 調(diào)用之后的代碼開始執(zhí)行,但它們各自運(yùn)行在獨(dú)立的內(nèi)存空間中。


2


vfork() 系統(tǒng)調(diào)用

函數(shù)原型如下:


#include <sys/types.h>#include <unistd.h>pid_t vfork(void);



返回值:vfork() 的返回值與 fork() 相同。在父進(jìn)程中,返回子進(jìn)程的 PID;在子進(jìn)程中,返回 0;如果出錯(cuò),則返回 -1 并設(shè)置 errno。


2.1、工作機(jī)制

vfork() 與 fork() 類似,用于創(chuàng)建一個(gè)子進(jìn)程,但它有不同的內(nèi)存管理機(jī)制。


vfork() 創(chuàng)建的子進(jìn)程與父進(jìn)程共享相同的地址空間,這意味著子進(jìn)程在調(diào)用 exec() 或 _exit() 之前,不會(huì)復(fù)制父進(jìn)程的內(nèi)存空間。這使得 vfork() 比 fork() 更加高效,特別是在子進(jìn)程很快就要執(zhí)行新的程序時(shí)。


共享地址空間:由于 vfork() 是為了在子進(jìn)程立即調(diào)用 exec() 或 _exit() 的場(chǎng)景下優(yōu)化的,因此子進(jìn)程和父進(jìn)程在 exec() 或 _exit() 之前共享同一內(nèi)存空間。這意味著如果子進(jìn)程在此期間修改了共享的內(nèi)存數(shù)據(jù),可能會(huì)導(dǎo)致不可預(yù)知的后果。


執(zhí)行順序:vfork() 保證子進(jìn)程會(huì)先運(yùn)行,直到調(diào)用 exec() 或 _exit() 后,父進(jìn)程才會(huì)繼續(xù)執(zhí)行。這種行為確保了父進(jìn)程不會(huì)在子進(jìn)程完成執(zhí)行之前訪問可能被修改的共享內(nèi)存。


2.2、使用場(chǎng)景

vfork() 適用于子進(jìn)程需要立即調(diào)用 exec() 來執(zhí)行新程序的場(chǎng)景。例如,在 shell 腳本中執(zhí)行外部命令時(shí),vfork() 可以提高效率。但由于 vfork() 在某些情況下會(huì)帶來潛在的安全風(fēng)險(xiǎn)(例如子進(jìn)程誤修改父進(jìn)程的內(nèi)存),現(xiàn)代系統(tǒng)通常更推薦使用優(yōu)化后的 fork()。


#include <stdio.h>#include <unistd.h>#include <sys/types.h> int main() {    pid_t pid = vfork(); // 創(chuàng)建子進(jìn)程     if (pid < 0) {        // vfork() 失敗        fprintf(stderr, "vfork() 失敗n");        return 1;    } else if (pid == 0) {        // 子進(jìn)程:立即執(zhí)行新的程序        execlp("/bin/ls", "ls", NULL); // 執(zhí)行 ls 命令        _exit(0); // 使用 _exit 確??焖偻顺鲎舆M(jìn)程    } else {        // 父進(jìn)程        printf("這是父進(jìn)程n");    }     return 0;}


在這個(gè)例子中,vfork() 創(chuàng)建了一個(gè)子進(jìn)程,并立即使用 execlp() 執(zhí)行 ls 命令。由于 vfork() 子進(jìn)程在執(zhí)行 exec() 之前與父進(jìn)程共享內(nèi)存,因此在調(diào)用 exec() 之前不能修改父進(jìn)程的數(shù)據(jù),否則可能導(dǎo)致程序行為不確定。


fork() 和 vfork() 的區(qū)別總結(jié):

  • 內(nèi)存管理:fork() 通過寫時(shí)復(fù)制為子進(jìn)程創(chuàng)建獨(dú)立的內(nèi)存空間,而 vfork() 讓子進(jìn)程與父進(jìn)程共享內(nèi)存空間,直到子進(jìn)程執(zhí)行 exec() 或 _exit()。

  • 效率:vfork() 比 fork() 更高效,特別是在子進(jìn)程需要立即執(zhí)行新程序時(shí)。但由于現(xiàn)代 Linux 內(nèi)核的寫時(shí)復(fù)制優(yōu)化,fork() 的效率也得到了顯著提升。

  • 安全性:fork() 更加安全可靠,因?yàn)樗鼮樽舆M(jìn)程分配了獨(dú)立的內(nèi)存空間。而 vfork() 可能會(huì)帶來潛在的風(fēng)險(xiǎn),建議在絕對(duì)需要優(yōu)化性能的情況下使用。


使用建議:

  • 優(yōu)先使用 fork():由于現(xiàn)代 Linux 系統(tǒng)已經(jīng)優(yōu)化了 fork(),在大多數(shù)情況下使用 fork() 是更為安全和通用的選擇。尤其是在編寫復(fù)雜的應(yīng)用程序時(shí),fork() 可以減少不確定性和潛在的錯(cuò)誤。

  • 在特定場(chǎng)景下使用 vfork():如果需要?jiǎng)?chuàng)建子進(jìn)程并立即調(diào)用 exec(),可以考慮使用 vfork() 以提高效率。但應(yīng)確保在調(diào)用 exec() 或 _exit() 之前,不會(huì)對(duì)父進(jìn)程的內(nèi)存空間進(jìn)行任何修改。


理解 fork() 和 vfork() 的工作原理和差異,對(duì)于設(shè)計(jì)和實(shí)現(xiàn)高效并發(fā)的 Linux 程序至關(guān)重要。在不同的應(yīng)用場(chǎng)景中,根據(jù)具體需求選擇合適的系統(tǒng)調(diào)用,將有助于提高程序的效率和穩(wěn)定性。


*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。



關(guān)鍵詞: 嵌入式 Linux

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉