中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

請人做網(wǎng)站得多少錢雅詩蘭黛網(wǎng)絡(luò)營銷策劃書

請人做網(wǎng)站得多少錢,雅詩蘭黛網(wǎng)絡(luò)營銷策劃書,四川省查詢建設(shè)證書的網(wǎng)站,網(wǎng)站可以做懷孕單嗎一、進(jìn)程創(chuàng)建:fork函數(shù) 我們在命令行中輸入man fork 即可得到fork函數(shù)的函數(shù)接口的函數(shù)的使用方法。 我們可以看到,fork函數(shù)位于man手冊的第2部分,由于第2部分通常是用于描述系統(tǒng)調(diào)用和庫函數(shù),所以我們可以了解到fork函數(shù)實際是一…

一、進(jìn)程創(chuàng)建:fork函數(shù)

我們在命令行中輸入man fork 即可得到fork函數(shù)的函數(shù)接口的函數(shù)的使用方法。

?我們可以看到,fork函數(shù)位于man手冊的第2部分,由于第2部分通常是用于描述系統(tǒng)調(diào)用和庫函數(shù),所以我們可以了解到fork函數(shù)實際是一個系統(tǒng)調(diào)用函數(shù)。

接下來,我們先了解一下什么是系統(tǒng)調(diào)用函數(shù)?

系統(tǒng)調(diào)用函數(shù)是操作系統(tǒng)提供給用戶程序或應(yīng)用程序的一組接口,通過這些接口,用戶程序可以請求操作系統(tǒng)執(zhí)行特定的操作,如文件操作、進(jìn)程管理、網(wǎng)絡(luò)通信等。系統(tǒng)調(diào)用函數(shù)允許用戶程序訪問操作系統(tǒng)的底層功能,以完成對硬件資源的管理和控制。

系統(tǒng)調(diào)用函數(shù)與一般的函數(shù)調(diào)用有所不同。一般的函數(shù)調(diào)用是在用戶程序內(nèi)部進(jìn)行的,而系統(tǒng)調(diào)用函數(shù)是用戶程序與操作系統(tǒng)之間的通信方式。當(dāng)用戶程序調(diào)用系統(tǒng)調(diào)用函數(shù)時,會觸發(fā)一個特殊的處理機(jī)制,將控制權(quán)轉(zhuǎn)移給操作系統(tǒng)內(nèi)核,執(zhí)行相應(yīng)的操作,然后將結(jié)果返回給用戶程序。

系統(tǒng)調(diào)用函數(shù)通常是由操作系統(tǒng)提供的庫函數(shù)封裝的,以便用戶程序更方便地調(diào)用。這些函數(shù)通常包含在標(biāo)準(zhǔn)庫中,例如在 C 語言中,可以通過?unistd.h?頭文件來訪問系統(tǒng)調(diào)用函數(shù)。

常見的系統(tǒng)調(diào)用函數(shù)包括?fork()、exec()open()、read()、write()?等,它們提供了對文件系統(tǒng)、進(jìn)程管理、內(nèi)存管理、網(wǎng)絡(luò)通信等底層功能的訪問。系統(tǒng)調(diào)用函數(shù)是編寫操作系統(tǒng)相關(guān)程序和系統(tǒng)編程的重要工具,也是操作系統(tǒng)與用戶程序之間的橋梁。

如果不理解,我們先記住加粗藍(lán)字描述的部分。?

在操作系統(tǒng)中,用戶程序處于用戶態(tài)(用戶層),而操作系統(tǒng)內(nèi)核處于內(nèi)核態(tài)(核心層)。用戶程序不能直接訪問系統(tǒng)的硬件資源或執(zhí)行特權(quán)指令,而是通過系統(tǒng)調(diào)用接口來請求操作系統(tǒng)執(zhí)行特定的任務(wù),包括對硬件資源的管理和控制。

通過系統(tǒng)調(diào)用接口,用戶程序可以向操作系統(tǒng)發(fā)出請求,比如讀寫文件、創(chuàng)建進(jìn)程、進(jìn)行網(wǎng)絡(luò)通信等。操作系統(tǒng)會根據(jù)請求執(zhí)行相應(yīng)的操作,然后將結(jié)果返回給用戶程序。這樣的設(shè)計有效地保護(hù)了系統(tǒng)的穩(wěn)定性和安全性,同時也提供了一種方便而有效的方式,讓用戶程序與系統(tǒng)進(jìn)行交互。

?fork函數(shù)詳解:

fork函數(shù)從已存在進(jìn)程中創(chuàng)建一個新進(jìn)程。新進(jìn)程為子進(jìn)程,而原進(jìn)程為父進(jìn)程。

  • 接口

    #include <unistd.h>
    pid_t fork(void);
    
  • 作用
    fork()?函數(shù)用于創(chuàng)建一個新的進(jìn)程,該進(jìn)程是調(diào)用進(jìn)程的副本。子進(jìn)程與父進(jìn)程幾乎完全相同,包括代碼段、數(shù)據(jù)段、堆棧等。在子進(jìn)程中,fork()?返回 0,而在父進(jìn)程中,它返回新創(chuàng)建子進(jìn)程的 PID(進(jìn)程標(biāo)識符)。

  • 返回值

    • 在父進(jìn)程中,fork()?返回新創(chuàng)建子進(jìn)程的 PID。
    • 在子進(jìn)程中,fork()?返回 0。
    • 如果?fork() 失敗,返回值為 -1,表示創(chuàng)建子進(jìn)程失敗。
  • 進(jìn)程的執(zhí)行

    • 子進(jìn)程從?fork()?返回的地方【return】開始執(zhí)行,而父進(jìn)程則繼續(xù)執(zhí)行它的代碼。這意味著在?fork()?調(diào)用之后,父進(jìn)程和子進(jìn)程會并行執(zhí)行。
  • 錯誤處理
    如果?fork()?失敗,返回值為 -1。失敗的原因可能是系統(tǒng)資源不足或者進(jìn)程數(shù)達(dá)到了限制。

  • 注意事項

    • 在?fork()?后,父子進(jìn)程共享文件描述符,這意味著在一個進(jìn)程中打開的文件在另一個進(jìn)程中也是打開的。如果不適當(dāng)?shù)靥幚?#xff0c;可能會導(dǎo)致意想不到的結(jié)果。
    • 子進(jìn)程通常需要調(diào)用 exec?系列函數(shù)來加載新的程序,以便替換掉自己的內(nèi)存映像。否則,子進(jìn)程將繼承父進(jìn)程的內(nèi)存映像,可能會導(dǎo)致一些意外的行為。

?接下來我們來看一段程序:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
int main()
{printf("父進(jìn)程開始運行!!!\n");pid_t id = fork();if(id == 0){printf("我是子進(jìn)程!!!\n");sleep(1);}else if(id > 0){printf("我是父進(jìn)程!!!\n");sleep(1);}else {perror("進(jìn)程創(chuàng)建失敗!!!\n");}return 0;
}

?這段代碼的結(jié)果是這樣的:

?接下來我們來詳細(xì)聊一下fork函數(shù)。相信大家都有這樣的疑問:

1、為什么fork()函數(shù)可以有兩個返回值,也就是函數(shù)會返回兩次,這和我們平時見到的函數(shù)不同。

當(dāng)進(jìn)程調(diào)用?fork()?函數(shù)時,控制會轉(zhuǎn)移到操作系統(tǒng)內(nèi)核中執(zhí)行?fork()?函數(shù)的代碼。在內(nèi)核中,fork()?函數(shù)主要完成以下操作:

  1. 創(chuàng)建新的進(jìn)程控制塊(Process Control Block,PCB):內(nèi)核會為新的子進(jìn)程分配一個唯一的進(jìn)程標(biāo)識符(PID),并在內(nèi)存中為其創(chuàng)建一個新的進(jìn)程控制塊(PCB)。這個 PCB 將包含子進(jìn)程的運行狀態(tài)、程序計數(shù)器、堆棧指針、文件描述符等信息。

  2. 復(fù)制父進(jìn)程的地址空間以創(chuàng)建自己的地址空間:在大多數(shù)情況下,fork()?函數(shù)會創(chuàng)建子進(jìn)程的完整副本,包括代碼段、數(shù)據(jù)段、堆棧等。這意味著子進(jìn)程將會獲得與父進(jìn)程幾乎完全相同的內(nèi)存映像。這一步通常通過 Copy-On-Write(寫時復(fù)制)技術(shù)來實現(xiàn),即在子進(jìn)程需要修改內(nèi)存時才會進(jìn)行實際的復(fù)制操作。

  3. 將子進(jìn)程的狀態(tài)設(shè)置為就緒:一旦子進(jìn)程的地址空間準(zhǔn)備好,內(nèi)核將其狀態(tài)設(shè)置為就緒態(tài),以便在合適的時機(jī)可以被調(diào)度執(zhí)行。

  4. 返回不同的值:在內(nèi)核中,fork()?函數(shù)會返回兩次,一次是在父進(jìn)程的上下文中返回子進(jìn)程的 PID,另一次是在子進(jìn)程的上下文中返回 0。這樣,父進(jìn)程和子進(jìn)程可以根據(jù)返回值來執(zhí)行不同的代碼路徑。

??

?在fork函數(shù)內(nèi)部,在執(zhí)行 return pid 之前,子進(jìn)程就已經(jīng)創(chuàng)建完成,所以 return pid 實際也是父子進(jìn)程的共享代碼部分,所以父進(jìn)程會執(zhí)行一次,返回子進(jìn)程的pid;而子進(jìn)程也會執(zhí)行一次 return pid?返回進(jìn)程是否創(chuàng)建完成的信息。

?2、為什么父進(jìn)程接收子進(jìn)程的PID,而子進(jìn)程返回0或-1?

  1. 父進(jìn)程接收子進(jìn)程的PID:父進(jìn)程在調(diào)用fork()函數(shù)后,會得到子進(jìn)程的PID作為返回值。通過這個PID,父進(jìn)程可以對子進(jìn)程進(jìn)行跟蹤、管理和通信。例如,父進(jìn)程可能會使用子進(jìn)程的PID來等待子進(jìn)程的結(jié)束狀態(tài)(通過waitpid()函數(shù)),或者向子進(jìn)程發(fā)送信號(通過kill()函數(shù))等。

  2. 子進(jìn)程返回0或-1:子進(jìn)程在fork()函數(shù)返回時,需要確定自己是父進(jìn)程還是子進(jìn)程。因此,子進(jìn)程通常會檢查fork()的返回值來確定自己的身份。具體來說:

    • 如果fork()返回0,則表示當(dāng)前進(jìn)程是子進(jìn)程。子進(jìn)程可以通過這個返回值來區(qū)別自己和父進(jìn)程,并且通常會在這個基礎(chǔ)上執(zhí)行特定的任務(wù)或代碼段。
    • 如果fork()返回-1,則表示進(jìn)程創(chuàng)建失敗。通常這種情況會發(fā)生在系統(tǒng)資源不足或者其他錯誤發(fā)生時。子進(jìn)程在這種情況下會立即退出或者采取相應(yīng)的錯誤處理措施。

由于fork()函數(shù)具有以上兩個特性,我們可以采取 if---else?語句對父子進(jìn)程進(jìn)行分流,這樣就可以讓父子進(jìn)程去做不同的事情,這也是我們后續(xù)進(jìn)行進(jìn)程替換的基礎(chǔ)。

3、父子進(jìn)程哪個先運行??

在一般情況下,無法確定父進(jìn)程和子進(jìn)程哪一個先運行。這取決于操作系統(tǒng)的調(diào)度策略以及各種競爭條件的發(fā)生情況。

通過上面的知識,我們了解到在fork函數(shù)內(nèi)部子進(jìn)程創(chuàng)建完成之后,父子進(jìn)程共享進(jìn)程創(chuàng)建完成之后的代碼,包括fork函數(shù)內(nèi)部的代碼。

二、進(jìn)程終止

進(jìn)程退出的場景:

  • 正常退出:進(jìn)程完成了它的任務(wù),并通過調(diào)用?exit()、_exit()函數(shù)或者在?main()?函數(shù)中使用?return?語句返回。在這種情況下,進(jìn)程會執(zhí)行清理操作,并返回退出狀態(tài)給操作系統(tǒng)。

  • 異常退出:進(jìn)程在執(zhí)行過程中遇到了錯誤或異常情況,無法繼續(xù)執(zhí)行下去。這可能是因為代碼中的錯誤、系統(tǒng)資源不足、權(quán)限不足等原因?qū)е碌?。在這種情況下,進(jìn)程可以調(diào)用?exit()?函數(shù)或者?_exit()?函數(shù)來立即終止程序執(zhí)行,并返回退出狀態(tài)給操作系統(tǒng)。

  • 收到信號:進(jìn)程可以收到來自操作系統(tǒng)或其他進(jìn)程發(fā)送的信號,例如 使用 kill 命令搭配SIGKILL 或 SIGTERM 等。

  • 父進(jìn)程終止:如果一個子進(jìn)程的父進(jìn)程終止了,而沒有等待子進(jìn)程完成(通過調(diào)用?wait()?或?waitpid()),則子進(jìn)程可能會成為孤兒進(jìn)程。在這種情況下,操作系統(tǒng)通常會將孤兒進(jìn)程的父進(jìn)程設(shè)置為 init 進(jìn)程(進(jìn)程號為 1),并由 init 進(jìn)程接管孤兒進(jìn)程的管理。孤兒進(jìn)程的退出方式與其他進(jìn)程相同。

  • 系統(tǒng)關(guān)閉:當(dāng)系統(tǒng)關(guān)閉或重啟時,所有正在運行的進(jìn)程都會被終止。操作系統(tǒng)通常會向所有進(jìn)程發(fā)送信號,以便它們有機(jī)會在關(guān)閉之前執(zhí)行清理操作。

  • 其他。。。

?進(jìn)程退出方法:

  1. 調(diào)用 exit()、_exit() 函數(shù)

  2. 在main()函數(shù)中使用return語句返回

  3. Ctrl + c 組合鍵 或者 使用 kill 命令搭配終止信號

?exit()函數(shù)、_exit()函數(shù)詳解

exit()?函數(shù)和?_exit()?函數(shù)都是用于終止程序的執(zhí)行

  1. exit()?函數(shù):

    • exit()?函數(shù)是標(biāo)準(zhǔn) C 庫中的函數(shù),用于正常終止程序的執(zhí)行,并返回退出狀態(tài)給操作系統(tǒng)。
    • 調(diào)用?exit()?函數(shù)會執(zhí)行以下步驟:
      1. 執(zhí)行所有注冊的退出處理程序(使用?atexit()?注冊的函數(shù))。
      2. 關(guān)閉所有打開的流(文件)。
      3. 刷新所有的緩沖區(qū)。
      4. 返回退出狀態(tài)給操作系統(tǒng)。
    • exit()?函數(shù)的原型在?<stdlib.h>?頭文件中聲明,其函數(shù)原型如下:
      #include <stdlib.h>
      void exit(int status);
      
    • status?參數(shù)是傳遞給操作系統(tǒng)的退出狀態(tài),通常用來指示程序的結(jié)束狀態(tài),一般約定 0 表示成功,非零值表示失敗或其他特定狀態(tài)。
    • exit()?函數(shù)在正常終止程序時應(yīng)該被調(diào)用,它會執(zhí)行標(biāo)準(zhǔn)的程序清理操作,并返回狀態(tài)給操作系統(tǒng)。
  2. _exit()?函數(shù):

    • _exit()?函數(shù)是系統(tǒng)調(diào)用,用于立即終止程序的執(zhí)行,不執(zhí)行標(biāo)準(zhǔn)的程序清理操作。
    • 調(diào)用?_exit()?函數(shù)會立即終止程序的執(zhí)行,并且不會執(zhí)行以下操作:
      1. 不執(zhí)行注冊的退出處理程序。
      2. 不關(guān)閉打開的流(文件)。
      3. 不刷新緩沖區(qū)。
    • _exit()?函數(shù)的原型在?<unistd.h>?頭文件中聲明,其函數(shù)原型如下:
      #include <unistd.h>
      void _exit(int status);
      
    • status?參數(shù)同樣是傳遞給操作系統(tǒng)的退出狀態(tài)。
    • _exit()?函數(shù)通常在需要立即終止程序執(zhí)行,并且不需要執(zhí)行標(biāo)準(zhǔn)清理操作時使用。比如,在子進(jìn)程中的錯誤處理中可以使用?_exit()?來避免執(zhí)行父進(jìn)程中的清理操作。

主要區(qū)別總結(jié):

  • exit()?是標(biāo)準(zhǔn) C 庫函數(shù),執(zhí)行標(biāo)準(zhǔn)的程序清理操作后返回退出狀態(tài)給操作系統(tǒng)。
  • _exit()?是系統(tǒng)調(diào)用,立即終止程序的執(zhí)行,不執(zhí)行標(biāo)準(zhǔn)的程序清理操作。

在使用時,通常情況下,應(yīng)該優(yōu)先使用?exit()?函數(shù)來正常終止程序,并執(zhí)行必要的清理操作。

exit最后也會調(diào)用exit, 但在調(diào)用exit之前,還做了其他工作:

  • 執(zhí)行標(biāo)準(zhǔn)的程序清理操作:調(diào)用?atexit()?注冊的清理函數(shù)、關(guān)閉文件描述符等
  • 關(guān)閉所有打開的流,所有的緩存數(shù)據(jù)均被寫入
  • 調(diào)用_exit

?通過上圖,我們可以明顯觀察到三者的差異。

return退出:
return是一種更常見的退出進(jìn)程方法。執(zhí)行return n;等同于執(zhí)行 exit(n) ,因為調(diào)用main的運行時函數(shù)會將main的返回值當(dāng)做 exit() 函數(shù)的參數(shù)。
?

三、進(jìn)程等待

在學(xué)習(xí)進(jìn)程等待前,我們要先了解什么是進(jìn)程等待?

進(jìn)程等待(Process Waiting)是指在操作系統(tǒng)中,一個進(jìn)程因為某種原因(通常是等待某些資源或條件滿足)而被阻塞,暫時無法執(zhí)行,需要等待直到滿足條件才能繼續(xù)執(zhí)行的狀態(tài)。這種狀態(tài)通常發(fā)生在進(jìn)程請求某種資源(如輸入/輸出設(shè)備、內(nèi)存、鎖等)而資源暫時不可用時,進(jìn)程會被置于等待狀態(tài),直到資源可用或條件滿足后才能繼續(xù)執(zhí)行。在進(jìn)程等待的過程中,操作系統(tǒng)可以將該進(jìn)程從可執(zhí)行狀態(tài)轉(zhuǎn)換為阻塞狀態(tài),以便其他可執(zhí)行的進(jìn)程有機(jī)會執(zhí)行。

舉個簡單的例子:在C語言中,我們使用printf函數(shù)向屏幕打印信息。我們讓下面的程序一直向顯示器打印信息,并觀察該進(jìn)程的狀態(tài)。

#include <stdio.h>
#include <unistd.h>int main()
{while(1){printf("I am a running process, my_pid:%d\n", getpid());sleep(1);}return 0;
}

看到這兒可能有同學(xué)會產(chǎn)生疑惑了:進(jìn)程明明是一直在運行呀,不應(yīng)該是R狀態(tài)(運行態(tài))嗎?為什么是S狀態(tài)(睡眠態(tài))呢?

其實這與CPU和顯示器的響應(yīng)速度有關(guān)。我們知道,CPU處理信息的速度是極快的,特別對于這種極其簡單的程序。但當(dāng)CPU每次處理完自身任務(wù)后,顯示器可能仍在處理之前的信息。而在這期間后續(xù)進(jìn)程需要等待顯示器準(zhǔn)備就緒,這會導(dǎo)致后續(xù)進(jìn)程處于阻塞狀態(tài),直到顯示器空閑并且操作系統(tǒng)將控制權(quán)交給它們。

?進(jìn)程等待的必要性
  • ?之前講過,子進(jìn)程退出,父進(jìn)程如果不管不顧,就可能造成“僵尸進(jìn)程”的問題,進(jìn)而造成內(nèi)存泄漏。
  • 另外,進(jìn)程一旦變成僵尸狀態(tài),那就刀槍不入,“殺人不眨眼”的kill -9 也無能為力,因為誰也沒有辦法 殺死一個已經(jīng)死去的進(jìn)程。
  • 最后,父進(jìn)程派給子進(jìn)程的任務(wù)完成的如何,我們需要知道。如,子進(jìn)程運行完成,結(jié)果對還是不對, 或者是否正常退出。 父進(jìn)程通過進(jìn)程等待的方式,回收子進(jìn)程資源,獲取子進(jìn)程退出信息?
進(jìn)程等待方法:wait() / waitpid() 函數(shù)詳解

wait()?和?waitpid()?函數(shù)都是用于父進(jìn)程等待子進(jìn)程結(jié)束的方法。它們的功能是類似的,但在使用上有些微妙的差別。

wait() 函數(shù)

wait()?函數(shù)的原型如下:

#include <sys/types.h>
#include <sys/wait.h>pid_t wait(int *status);
  • 參數(shù)?status?是一個指向整數(shù)的指針,用于存儲子進(jìn)程的退出狀態(tài)信息,不關(guān)心可以設(shè)置成NULL。
  • 返回值是被等待子進(jìn)程的進(jìn)程ID(PID),如果沒有子進(jìn)程或出錯,則返回 -1。

wait()?函數(shù)的作用是掛起當(dāng)前進(jìn)程,直到任何一個子進(jìn)程退出為止。當(dāng)子進(jìn)程結(jié)束時,父進(jìn)程會收到一個信號,并在收到信號后繼續(xù)執(zhí)行。此時,可以通過?status?參數(shù)獲取子進(jìn)程的退出狀態(tài)信息。

waitpid() 函數(shù)

waitpid()?函數(shù)的原型如下:

#include <sys/types.h>
#include <sys/wait.h>pid_t waitpid(pid_t pid, int *status, int options);
  • pid?參數(shù)指定要等待的子進(jìn)程ID。如果?pid?為 -1,則等待任意子進(jìn)程;如果為 0,則等待與當(dāng)前進(jìn)程組ID相同的任一子進(jìn)程;如果為正數(shù),則等待指定PID的子進(jìn)程;如果為負(fù)數(shù),則等待進(jìn)程組ID與?pid?絕對值相同的任一子進(jìn)程。
  • status?參數(shù)同樣是用于存儲子進(jìn)程退出狀態(tài)信息的指針,不關(guān)心可以設(shè)置成NULL。
  • options?參數(shù)是一組選項,用于指定等待行為的一些額外條件,如是否非阻塞等,如不使用可以設(shè)置為0,默認(rèn)阻塞等待。
  • waitpid()?函數(shù)的返回值有三種可能性:

    • 如果返回一個正值,這個值就是已經(jīng)終止的子進(jìn)程的進(jìn)程 ID(PID)。

    • 如果返回 0,表示調(diào)用了?WNOHANG?選項,并且當(dāng)前沒有已終止的子進(jìn)程。

    • 如果返回 -1,表示發(fā)生了錯誤,這時需要檢查?errno?來獲取具體的錯誤信息。

區(qū)別總結(jié)

  • wait()?函數(shù)只能等待任何子進(jìn)程退出,而?waitpid()?函數(shù)允許指定具體的子進(jìn)程ID。
  • waitpid()?函數(shù)還可以通過?options?參數(shù)指定一些額外的選項,如是否非阻塞等。
  • 兩個函數(shù)都會掛起調(diào)用它們的進(jìn)程,直到等待的子進(jìn)程退出為止。

?waitpid()函數(shù)options選項:

waitpid() 函數(shù)的?options?參數(shù)用于指定等待行為的一些額外條件,包括但不限于以下幾種選項:

  • WNOHANG:指定非阻塞模式。如果沒有子進(jìn)程退出,立即返回,不掛起父進(jìn)程。
  • WUNTRACED:也會等待已經(jīng)停止的子進(jìn)程退出,但不會等待已經(jīng)恢復(fù)執(zhí)行的子進(jìn)程。
  • WCONTINUED:等待已經(jīng)繼續(xù)執(zhí)行的子進(jìn)程退出。
  • WSTOPPED:等待已經(jīng)停止的子進(jìn)程退出,與?WUNTRACED?類似。
  • 這些選項可以單獨使用,也可以通過按位或運算組合使用。例如,options?可以是?WNOHANG | WUNTRACED,表示以非阻塞模式等待子進(jìn)程退出,并且同時等待已經(jīng)停止的子進(jìn)程退出。

  • 這些選項實際上是預(yù)先定義好的宏,在?sys/wait.h?頭文件中進(jìn)行了聲明。當(dāng)你使用這些宏時,編譯器會將其替換為相應(yīng)的整數(shù)值,以便在?waitpid()?函數(shù)中使用。

status參數(shù)詳解

status?參數(shù)是一個輸出型參數(shù),用于由進(jìn)程本身提供子進(jìn)程的退出狀態(tài)信息。當(dāng)子進(jìn)程退出時,其退出狀態(tài)會被寫入到?status?參數(shù)指向的內(nèi)存位置中,以供父進(jìn)程獲取。?

  • wait和waitpid,都有一個status參數(shù),該參數(shù)是一個輸出型參數(shù),由操作系統(tǒng)填充。
  • 如果傳遞NULL,表示不關(guān)心子進(jìn)程的退出狀態(tài)信息。
  • 否則,操作系統(tǒng)會根據(jù)該參數(shù),將子進(jìn)程的退出信息反饋給父進(jìn)程。
  • status不能簡單的當(dāng)作整形來看待,可以當(dāng)作位圖來看待,具體細(xì)節(jié)如下圖(只研究status低16比特位)

在status的低16比特位當(dāng)中,高8位表示進(jìn)程的退出狀態(tài),即退出碼。進(jìn)程若是被信號所殺,則低7位表示終止信號,而第8位比特位是core dump標(biāo)志。?

我們通過位運算操作就可以得出程序的退出狀態(tài)和終止信號:

exit_code = (status >> 8) & 0xff; //退出狀態(tài),取9~16位
exit_signal = status & 0x7f;      //終止信號,取1~7位

同時,庫中也提供了兩個宏來代替上面的運算:

  • WEXITSTATUS(status)?宏函數(shù)用于提取子進(jìn)程的退出碼,前提是該子進(jìn)程是通過正常終止而退出的。其原型為:

    int WEXITSTATUS(int status);
    

    當(dāng)且僅當(dāng)?WIFEXITED(status)?返回真(非零值)時,才應(yīng)該用?WEXITSTATUS(status)。這個宏可以幫助你獲取子進(jìn)程退出時傳遞給?exit()?函數(shù)的退出碼,通常用于查看子進(jìn)程的退出狀態(tài)。

  • WIFEXITED(status)?宏函數(shù)用于檢查子進(jìn)程是否為正常終止,本質(zhì)是檢查是否收到信號,其原型為:

    int WIFEXITED(int status);
    

    如果子進(jìn)程正常終止并成功退出,則該宏返回真(非零值),否則返回假(0)。這個宏可以幫助你確定子進(jìn)程是否是通過調(diào)用?exit()?或?_exit()?等函數(shù)正常退出的。

?所以也可以如下表示:

exit_code = WEXITSTATUS(status);  //獲取退出碼
exit_signal = WIFEXITED(status);  //是否正常退出

使用示例:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{pid_t id = fork();if(id == 0){//childint count = 10;while(count--){printf("I am child...PID:%d, PPID:%d\n", getpid(), getppid());sleep(1);}exit(0);}//fatherint status = 0;pid_t ret = wait(&status);//pid_t ret = wait(-1, &status, 0); 此方法同上if(ret > 0){//wait successprintf("wait child success...\n");if(WIFEXITED(status)){//exit normalprintf("exit code:%d\n", WEXITSTATUS(status));}}sleep(1);return 0;
}

?可以看到父進(jìn)程成功等待到子進(jìn)程,且子進(jìn)程的是正常退出。

如果我們使用kill -9 信號使子進(jìn)程強(qiáng)制退出呢?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{pid_t id = fork();if(id == 0){//childint count = 20;while(count--){printf("I am child...PID:%d, PPID:%d\n", getpid(), getppid());sleep(1);}exit(0);}//fatherint status = 0;pid_t ret = waitpid(-1, &status, 0);if(ret > 0){//wait successprintf("wait child success...\n");//判斷是否正常退出if(WIFEXITED(status)){//exit normalprintf("exit code:%d\n", WEXITSTATUS(status));//正常退出則打印退出碼}else {//exit abnormalprintf("exit_signal:%d\n",status & 0x7f);}}sleep(3);return 0;
}

?可以看到,當(dāng)使用kill -9 強(qiáng)制終止子進(jìn)程時,父進(jìn)程依然等待成功,但是由于使用的是信號,所以是異常退出,最終程序只打印出了退出信號。

進(jìn)程的阻塞等待方式:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>int main()
{pid_t pid;pid = fork();if (pid < 0) {printf("%s fork error\n", __FUNCTION__);return 1;}else if (pid == 0) { //childprintf("child is run, pid is : %d\n", getpid());sleep(5);exit(257);}else {int status = 0;pid_t ret = waitpid(-1, &status, 0);//阻塞式等待,等待5Sprintf("this is test for wait\n");if (WIFEXITED(status) && ret == pid) {printf("wait child 5s success, child return code is :%d.\n", WEXITSTATUS(status));}else {printf("wait child failed, return.\n");return 1;}}return 0;
}

上述所給例子中,當(dāng)子進(jìn)程未退出時,父進(jìn)程都在一直等待子進(jìn)程退出,在等待期間,父進(jìn)程不能做任何事情,這種等待叫做阻塞等待。

實際上我們可以讓父進(jìn)程不要一直等待子進(jìn)程退出,而是當(dāng)子進(jìn)程未退出時父進(jìn)程可以做一些自己的事情,當(dāng)子進(jìn)程退出時再讀取子進(jìn)程的退出信息,即非阻塞等待。

我們將options參數(shù)設(shè)置為WNOHANG:指定非阻塞模式。如果沒有子進(jìn)程退出,立即返回,不掛起父進(jìn)程。并且使用循環(huán)進(jìn)行輪番檢測,如果等待不成功,那父進(jìn)程就去做別的事情。過段時間再去調(diào)用waitpid函數(shù),等待子進(jìn)程成功后,父進(jìn)程才會退出。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{pid_t id = fork();if (id == 0) {//childint count = 3;while (count--) {printf("child do something...PID:%d, PPID:%d\n", getpid(), getppid());sleep(3);}exit(0);}//fatherwhile (1) {int status = 0;pid_t ret = waitpid(id, &status, WNOHANG);if (ret > 0) //父進(jìn)程等待成功{printf("wait child success...\n");printf("exit code:%d\n", WEXITSTATUS(status));break;}else if (ret == 0) //子進(jìn)程仍在運行{printf("father do other things...\n");//可以穿插其他函數(shù)讓父進(jìn)程去做其他事情sleep(1);}else //waitpid返回-1,等待失敗,終止等待{printf("waitpid error...\n");break;}}return 0;
}

?四、進(jìn)程替換

進(jìn)程替換原理:

用fork創(chuàng)建子進(jìn)程后執(zhí)行的是和父進(jìn)程相同的程序(但有可能執(zhí)行不同的代碼分支),子進(jìn)程往往要調(diào)用一種exec函數(shù)以執(zhí)行另一個程序。當(dāng)進(jìn)程調(diào)用一種exec函數(shù)時,該進(jìn)程的用戶空間代碼和數(shù)據(jù)完全被新程序替換,從新程序的啟動例程開始執(zhí)行。調(diào)用exec并不創(chuàng)建新進(jìn)程,所以調(diào)用exec前后該進(jìn)程的id并未改變。

當(dāng)一個進(jìn)程執(zhí)行了進(jìn)程替換(如exec()系列函數(shù))后,它會被替換為另一個程序。

以下函數(shù)統(tǒng)稱exec函數(shù):?

  1. execl():

    • 函數(shù)接口:int execl(const char *path, const char *arg0, ... /* (char *) NULL */);
    • 參數(shù)解釋:
      • path:要執(zhí)行的程序的路徑。
      • arg0:程序的名稱,一般來說是?path?的基本文件名。
      • ...:傳遞給新程序的參數(shù)列表,以 NULL 結(jié)尾。
  2. execle():

    • 函數(shù)接口:int execle(const char *path, const char *arg0, ..., /* (char *) NULL, char *const envp[] */);
    • 參數(shù)解釋:
      • 除了 execl() 的參數(shù)外,還接受一個額外的參數(shù)?envp,用于傳遞環(huán)境變量數(shù)組。
  3. execlp():

    • 函數(shù)接口:int execlp(const char *file, const char *arg0, ... /* (char *) NULL */);
    • 參數(shù)解釋:
      • file:要執(zhí)行的程序的文件名,會在環(huán)境變量 PATH 指定的路徑中搜索。
      • 其他參數(shù)與 execl() 類似。
  4. execv():

    • 函數(shù)接口:int execv(const char *path, char *const argv[]);
    • 參數(shù)解釋:
      • path:要執(zhí)行的程序的路徑。
      • argv[]:傳遞給新程序的參數(shù)數(shù)組,以 NULL 結(jié)尾。
  5. execvp():

    • 函數(shù)接口:int execvp(const char *file, char *const argv[]);
    • 參數(shù)解釋:
      • file:要執(zhí)行的程序的文件名,會在環(huán)境變量 PATH 指定的路徑中搜索。
      • argv[]:傳遞給新程序的參數(shù)數(shù)組,以 NULL 結(jié)尾。
  6. execve():

    • 函數(shù)接口:int execve(const char *filename, char *const argv[], char *const envp[]);
    • 參數(shù)解釋:
      • filename:要執(zhí)行的程序的路徑。
      • argv[]:傳遞給新程序的參數(shù)數(shù)組,以 NULL 結(jié)尾。
      • envp[]:環(huán)境變量數(shù)組。
  7. execvpe():

    • 函數(shù)接口:int execvpe(const char *file, char *const argv[], char *const envp[]);
    • 參數(shù)解釋:
      • file:要執(zhí)行的程序的文件名,會在環(huán)境變量 PATH 指定的路徑中搜索。
      • argv[]:傳遞給新程序的參數(shù)數(shù)組,以 NULL 結(jié)尾。
      • envp[]:環(huán)境變量數(shù)組。

這些函數(shù)的參數(shù)解釋中,path代表要執(zhí)行的程序的路徑,?file?代表要執(zhí)行的可執(zhí)行文件的文件名,argv[]?是傳遞給新程序的參數(shù)數(shù)組,而?envp[]?是環(huán)境變量數(shù)組。函數(shù)的返回值為 -1 表示執(zhí)行失敗,具體的錯誤信息可以通過查看 errno 來獲取。進(jìn)程替換如果調(diào)用成功則加載新的程序從啟動代碼開始執(zhí)行,不再返回到原來的程序中。?

命名理解

  • 這些函數(shù)用于執(zhí)行其他程序。
  • 以 “l(fā)(list)” 結(jié)尾的函數(shù)(如 execl、execle)采用參數(shù)列表的方式傳遞參數(shù),參數(shù)個數(shù)在函數(shù)調(diào)用時需要提前確定。
  • 以 “v(vector)” 結(jié)尾的函數(shù)(如 execv、execvp)采用指針數(shù)組的方式傳遞參數(shù),參數(shù)個數(shù)在數(shù)組的結(jié)束標(biāo)志(NULL)前確定。
  • 以 “p(path)” 結(jié)尾的函數(shù)(如 execlp、execvp、execvpe)可以根據(jù)環(huán)境變量 PATH 來搜索可執(zhí)行文件。
  • 以 “e(env)” 結(jié)尾的函數(shù)(如 execle、execve、execvpe)允許設(shè)置環(huán)境變量。
  • execvpe() 在搜索可執(zhí)行文件時除了搜索 PATH 環(huán)境變量外,還可以通過傳遞一個環(huán)境變量數(shù)組來搜索。

應(yīng)用舉例:?

#include <unistd.h>
int main()
{char* const argv[] = { "ps", "-ef", NULL };char* const envp[] = { "PATH=/bin:/usr/bin", "TERM=console", NULL };execl("/bin/ps", "ps", "-ef", NULL);// 帶p的,可以使用環(huán)境變量PATH,無需寫全路徑execlp("ps", "ps", "-ef", NULL);// 帶e的,需要自己組裝環(huán)境變量execle("ps", "ps", "-ef", NULL, envp);execv("/bin/ps", argv);// 帶p的,可以使用環(huán)境變量PATH,無需寫全路徑execvp("ps", argv);// 帶e的,需要自己組裝環(huán)境變量execve("/bin/ps", argv, envp);exit(0);
}

?事實上,只有execve才是真正的系統(tǒng)調(diào)用,其它五個函數(shù)最終都是調(diào)用的execve,所以execve在man手冊的第2節(jié),而其它五個函數(shù)在man手冊的第3節(jié),也就是說其他五個函數(shù)實際上是對系統(tǒng)調(diào)用execve進(jìn)行了封裝,以滿足不同用戶的不同調(diào)用場景的。

http://m.risenshineclean.com/news/63586.html

相關(guān)文章:

  • 網(wǎng)站開發(fā)者取色工具ai智能搜索引擎
  • 地圖網(wǎng)站怎么做的廣告投放平臺
  • 洛陽做網(wǎng)站的百度上海分公司
  • 做短視頻網(wǎng)站需要審批搜索關(guān)鍵詞網(wǎng)站
  • php網(wǎng)站開發(fā)看什么書拼多多seo 優(yōu)化軟件
  • 關(guān)于電商運營的知識點百度關(guān)鍵詞seo排名軟件
  • 哪個網(wǎng)站可以做淘寶代碼百度號碼認(rèn)證平臺官網(wǎng)
  • 南通公司做網(wǎng)站百度人工客服
  • 短網(wǎng)址生成器有哪些網(wǎng)站seo優(yōu)化方案項目策劃書
  • 諸暨網(wǎng)站制作seo公司賺錢嗎
  • 如何用自己公司網(wǎng)站做郵箱c++線上培訓(xùn)機(jī)構(gòu)哪個好
  • 團(tuán)購網(wǎng)站 網(wǎng)上 收費 系統(tǒng)項目營銷策劃方案
  • vs2015做的網(wǎng)站網(wǎng)站外鏈購買平臺
  • asp net網(wǎng)站開發(fā)語言的特點網(wǎng)絡(luò)推廣軟文
  • 15年做啥網(wǎng)站能致富seo發(fā)包軟件
  • 專做網(wǎng)站漏掃的工具濟(jì)南seo優(yōu)化公司
  • 舟山市建設(shè)工程質(zhì)量監(jiān)督站網(wǎng)站網(wǎng)址導(dǎo)航該如何推廣
  • 英文網(wǎng)站外鏈查詢關(guān)鍵詞可以分為哪三類
  • 專業(yè)科技網(wǎng)站建設(shè)重慶網(wǎng)站建設(shè)技術(shù)外包
  • 做網(wǎng)站分辨率修改太原高級seo主管
  • 手機(jī)兼職在家掙錢的方法菏澤資深seo報價
  • 網(wǎng)站黑白了響應(yīng)式網(wǎng)站模板的應(yīng)用
  • 免費大氣網(wǎng)站模板站長之家seo
  • 哪些網(wǎng)站可以做ppt賺錢寧波seo公司哪家好
  • 做網(wǎng)站設(shè)計文字大小怎么設(shè)定重慶seo網(wǎng)頁優(yōu)化
  • 青島商城網(wǎng)站建設(shè)seo研究協(xié)會網(wǎng)是干什么的
  • 如何對django網(wǎng)站做測試大數(shù)據(jù)比較好的培訓(xùn)機(jī)構(gòu)
  • wordpress 建站公司電商運營自學(xué)全套教程
  • 網(wǎng)站制作推薦新鴻儒seo引擎優(yōu)化
  • 五金配件網(wǎng)站建設(shè)報價鄭州網(wǎng)站關(guān)鍵詞推廣