<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 分叉,第 2 部分:Fork,Exec,等等 > 原文:<https://github.com/angrave/SystemProgramming/wiki/Forking%2C-Part-2%3A-Fork%2C-Exec%2C-Wait> ## 模式 ## 以下'exec'示例有什么作用? ```c #include <unistd.h> #include <fcntl.h> // O_CREAT, O_APPEND etc. defined here int main() { close(1); // close standard out open("log.txt", O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); puts("Captain's log"); chdir("/usr/include"); // execl( executable, arguments for executable including program name and NULL at the end) execl("/bin/ls", /* Remaining items sent to ls*/ "/bin/ls", ".", (char *) NULL); // "ls ." perror("exec failed"); return 0; // Not expected } ``` 上面的代碼中沒有錯誤檢查(我們假設 close,open,chdir 等按預期工作)。 * open:將使用最低可用文件描述符(即 1);如此標準現在轉到日志文件。 * chdir:將當前目錄更改為/ usr / include * execl:用/ bin / ls 替換程序映像并調用其 main()方法 * perror:我們不希望到達這里 - 如果我們這樣做,那么 exec 就失敗了。 ## 微妙的分叉蟲 這段代碼出了什么問題 ```c #include <unistd.h> #define HELLO_NUMBER 10 int main(){ pid_t children[HELLO_NUMBER]; int i; for(i = 0; i < HELLO_NUMBER; i++){ pid_t child = fork(); if(child == -1){ break; } if(child == 0){ //I am the child execlp("ehco", "echo", "hello", NULL); } else{ children[i] = child; } } int j; for(j = 0; j < i; j++){ waitpid(children[j], NULL, 0); } return 0; } ``` 我們錯誤拼寫了`ehco`,所以我們不能`exec`它。這是什么意思?我們只是創建了 2 ** 10 個進程,而不是創建 10 個進程,而是對我們的機器進行轟炸。我們怎么能阻止這個?在 exec 之后立即退出,以防 exec 失敗,我們不會最終轟炸我們的機器。 ## 孩子從父母那里繼承了什么? * 打開文件句柄。如果父母后來尋求回到文件的開頭那么這也會影響孩子(反之亦然)。 * 信號處理程序 * 當前的工作目錄 * 環境變量 有關詳細信息,請參見 [fork 手冊頁](http://linux.die.net/man/2/fork)。 ## 子進程與父進程有什么不同? 進程 ID 不同。在調用`getppid()`的子代中(注意兩個'p')將給出與在父代中調用 getpid()相同的結果。有關更多詳細信息,請參見 fork 手冊頁。 ## 我該如何等待孩子完成? 使用`waitpid`或`wait`。父進程將暫停,直到`wait`(或`waitpid`)返回。請注意,這個解釋掩蓋了重新開始的討論。 ## 什么是 fork-exec-wait 模式 常見的編程模式是調用`fork`,然后調用`exec`和`wait`。原始進程調用 fork,它創建一個子進程。然后,子進程使用 exec 開始執行新程序。同時父母使用`wait`(或`waitpid`)等待子進程完成。請參閱下面的完整代碼示例。 ## 如何啟動同時運行的后臺進程? 不要等他們!您的父進程可以繼續執行代碼,而無需等待子進程。注意在實踐中,通過在調用 exec 之前調用打開的文件描述符上的`close`,后臺進程也可以與父進程和輸出流斷開連接。 但是,在父完成之前完成的子進程可能會變成僵尸。有關更多信息,請參閱僵尸頁面。 ## 植物大戰僵尸 ## 好父母不要讓自己的孩子成為僵尸! 當一個孩子完成(或終止)時,它仍占用內核進程表中的一個槽。只有當孩子'等待'時,才能再次使用該插槽。 一個長期運行的程序可以通過不斷創建進程來創建許多僵尸,而不會為它們進行`wait`處理。 ## 太多僵尸會有什么影響? 最終,內核進程表中沒有足夠的空間來創建新進程。因此`fork()`會失敗并且可能使系統難以/不可能使用 - 例如只需登錄就需要新的進程! ## 系統如何幫助預防僵尸? 一旦一個進程完成,它的任何子進程都將被分配給“init” - 第一個進程的 pid 為 1.因此這些孩子會看到 getppid()返回值為 1.這些孤兒最終會完成,并在短時間內成為一個僵尸。幸運的是,init 進程自動等待其所有子進程,從而從系統中刪除這些僵尸。 ## 我該如何預防僵尸? (警告:簡化回答) 等你的孩子! ```c waitpid(child, &status, 0); // Clean up and wait for my child process to finish. ``` 請注意,我們假設獲得 SIGCHLD 事件的唯一原因是孩子已經完成(這不完全正確 - 請參閱手冊頁以獲取更多詳細信息)。 強大的實現還可以檢查中斷狀態并將上述內容包含在循環中。繼續閱讀,討論更強大的實現。 ## 我怎樣才能異步等待使用 SIGCHLD 的孩子? (高級) 警告:本節使用的信號尚未完全介紹。當子進程完成時,父進程獲取信號 SIGCHLD,因此信號處理程序可以等待進程。稍微簡化的版本如下所示。 ```c pid_t child; void cleanup(int signal) { int status; waitpid(child, &status, 0); write(1,"cleanup!\n",9); } int main() { // Register signal handler BEFORE the child can finish signal(SIGCHLD, cleanup); // or better - sigaction child = fork(); if (child == -1) { exit(EXIT_FAILURE);} if (child == 0) { /* I am the child!*/ // Do background stuff e.g. call exec } else { /* I'm the parent! */ sleep(4); // so we can see the cleanup puts("Parent is done"); } return 0; } ``` 然而,上面的例子忽略了幾個微妙的要點: * 不止一個孩子可能已經完成但父母只會獲得一個 SIGCHLD 信號(信號沒有排隊) * 可以出于其他原因發送 SIGCHLD 信號(例如暫時停止子進程) 收獲僵尸的更強大的代碼如下所示。 ```c void cleanup(int signal) { int status; while (waitpid((pid_t) (-1), 0, WNOHANG) > 0) {} } ``` ## 那么什么是環境變量? 環境變量是系統為所有進程保留的變量。您的系統現在已經設置好了!在 Bash 中,您可以查看其中的一些內容 ``` $ echo $HOME /home/bhuvy $ echo $PATH /usr/local/sbin:/usr/bin:... ``` 你會如何在 C / C ++中獲得這些?您可以使用`getenv`和`setenv`功能 ```c char* home = getenv("HOME"); // Will return /home/bhuvy setenv("HOME", "/home/bhuvan", 1 /*set overwrite to true*/ ); ``` ## 是的,那么這些環境變量如何對父母/孩子意味著什么呢? 那么每個進程都會獲得自己的環境變量字典,并將其復制到子進程中。這意味著,如果父級更改其環境變量,則不會將其傳輸給子級,反之亦然。如果你想用不同于父(或任何其他進程)的環境變量執行程序,這在 fork-exec-wait 三部曲中很重要。 例如,您可以編寫一個循環遍歷所有時區的 C 程序,并執行`date`命令以打印所有本地的日期和時間。環境變量用于各種程序,因此修改它們很重要。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看