国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

這篇具有很好參考價(jià)值的文章主要介紹了Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、進(jìn)程的簡介

1、什么是進(jìn)程,進(jìn)程的概念

??進(jìn)程是一個(gè)動(dòng)態(tài)過程,而非靜態(tài)文件,它是程序的一次運(yùn)行過程,當(dāng)應(yīng)用程序被加載到內(nèi)存中運(yùn)行之后它就稱為了一個(gè)進(jìn)程,當(dāng)程序運(yùn)行結(jié)束后也就意味著進(jìn)程終止,這就是進(jìn)程的一個(gè)生命周期。

2、進(jìn)程狀態(tài)

??Linux 系統(tǒng)下進(jìn)程通常存在 6 種不同的狀態(tài),分為:就緒態(tài)、運(yùn)行態(tài)、僵尸態(tài)、 可中斷睡眠狀態(tài)(淺度睡眠)、不可中斷睡眠狀態(tài)(深度睡眠)以及暫停態(tài)。
??? 就緒態(tài)(Ready) : 指該進(jìn)程滿足被 CPU 調(diào)度的所有條件但此時(shí)并沒有被調(diào)度執(zhí)行,只要得到 CPU就能夠直接運(yùn)行;意味著該進(jìn)程已經(jīng)準(zhǔn)備好被 CPU 執(zhí)行,當(dāng)一個(gè)進(jìn)程的時(shí)間片到達(dá),操作系統(tǒng)調(diào)度程序會(huì)從就緒態(tài)鏈表中調(diào)度一個(gè)進(jìn)程;
??? 運(yùn)行態(tài): 指該進(jìn)程當(dāng)前正在被 CPU 調(diào)度運(yùn)行,處于就緒態(tài)的進(jìn)程得到 CPU 調(diào)度就會(huì)進(jìn)入運(yùn)行態(tài);
??? 僵尸態(tài): 僵尸態(tài)進(jìn)程其實(shí)指的就是僵尸進(jìn)程,指該進(jìn)程已經(jīng)結(jié)束、但其父進(jìn)程還未給它“收尸”;
??? 可中斷睡眠狀態(tài): 可中斷睡眠也稱為淺度睡眠,表示睡的不夠“死”,還可以被喚醒,一般來說可以通過信號來喚醒;
??? 不可中斷睡眠狀態(tài): 不可中斷睡眠稱為深度睡眠,深度睡眠無法被信號喚醒,只能等待相應(yīng)的條件成立才能結(jié)束睡眠狀態(tài)。把淺度睡眠和深度睡眠統(tǒng)稱為等待態(tài)(或者叫阻塞態(tài)) ,表示進(jìn)程處于一種等待狀態(tài),等待某種條件成立之后便會(huì)進(jìn)入到就緒態(tài);所以,處于等待態(tài)的進(jìn)程是無法參與進(jìn)程系統(tǒng)調(diào)度的。
??? 暫停態(tài): 暫停并不是進(jìn)程的終止,表示進(jìn)程暫停運(yùn)行,一般可通過信號將進(jìn)程暫停,譬如 SIGSTOP信號;處于暫停態(tài)的進(jìn)程是可以恢復(fù)進(jìn)入到就緒態(tài)的,譬如收到 SIGCONT 信號。一個(gè)新創(chuàng)建的進(jìn)程會(huì)處于就緒態(tài),只要得到 CPU 就能被執(zhí)行。以下列出了進(jìn)程各個(gè)狀態(tài)之間的轉(zhuǎn)換關(guān)系,如下所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

3、什么是進(jìn)程號

??Linux 系統(tǒng)下的每一個(gè)進(jìn)程都有一個(gè)進(jìn)程號(process ID,簡稱 PID),進(jìn)程號是一個(gè)正數(shù),用于唯一標(biāo)
識系統(tǒng)中的某一個(gè)進(jìn)程。

4、進(jìn)程間的通信方法(IPC)

??①管道通信:分別為有名管道和無名管道。
??②信號。
??③共享內(nèi)存。
??④消息隊(duì)列。
??⑤信號量。
??⑥套接字(socket)。

二、 fork()創(chuàng)建子進(jìn)程

Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

三、父、 子進(jìn)程間的文件共享

??調(diào)用 fork()函數(shù)之后,子進(jìn)程會(huì)獲得父進(jìn)程所有文件描述符的副本,這些副本的創(chuàng)建方式類似于 dup(),
這也意味著父、子進(jìn)程對應(yīng)的文件描述符均指向相同的文件表,如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

??由此可知,子進(jìn)程拷貝了父進(jìn)程的文件描述符表,使得父、子進(jìn)程中對應(yīng)的文件描述符指向了相同的文件表, 也意味著父、子進(jìn)程中對應(yīng)的文件描述符指向了磁盤中相同的文件,因而這些文件在父、子進(jìn)程間實(shí)現(xiàn)了共享,譬如,如果子進(jìn)程更新了文件偏移量,那么這個(gè)改變也會(huì)影響到父進(jìn)程中相應(yīng)文件描述符的位置偏移量。

1、實(shí)驗(yàn)1

??父進(jìn)程打開文件之后,然后 fork()創(chuàng)建子進(jìn)程,此時(shí)子進(jìn)程繼承了父進(jìn)程打開的文件描述符(父進(jìn)程文件描述符的副本) ,然后父、子進(jìn)程同時(shí)對文件進(jìn)行寫入操作。
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??上圖測試結(jié)果可知,此種情況下,父、子進(jìn)程分別對同一個(gè)文件進(jìn)行寫入操作,結(jié)果是接續(xù)寫,不管是父進(jìn)程,還是子進(jìn)程,在每次寫入時(shí)都是從文件的末尾寫入, 很像使用了 O_APPEND 標(biāo)志的效果。 其原因也非常簡單, 圖 9.6.1 中便給出了答案,子進(jìn)程繼承了父進(jìn)程的文件描述符,兩個(gè)文件描述符都指向了一個(gè)相同的文件表,意味著它們的文件偏移量是同一個(gè)、綁定在了一起,相互影響,子進(jìn)程改變了文件的位置偏移量就會(huì)作用到父進(jìn)程,同理,父進(jìn)程改變了文件的位置偏移量就會(huì)作用到子進(jìn)程。

2、實(shí)驗(yàn)2

??父進(jìn)程在調(diào)用 fork()之后,此時(shí)父進(jìn)程和子進(jìn)程都去打開同一個(gè)文件,然后再對文件進(jìn)行寫入操作。
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??上圖測試結(jié)果可知,這種文件共享方式實(shí)現(xiàn)的是一種兩個(gè)進(jìn)程分別各自對文件進(jìn)行寫入操作,因?yàn)楦?、子進(jìn)程的這兩個(gè)文件描述符分別指向的是不同的文件表,意味著它們有各自的文件偏移量,一個(gè)進(jìn)程修改了文件偏移量并不會(huì)影響另一個(gè)進(jìn)程的文件偏移量,所以寫入的數(shù)據(jù)會(huì)出現(xiàn)覆蓋的情況。

四、使用execl函數(shù)執(zhí)行新程序

??當(dāng)子進(jìn)程的工作不再是運(yùn)行父進(jìn)程的代碼段,而是運(yùn)行另一個(gè)新程序的代碼,那么這個(gè)時(shí)候子進(jìn)程可以通過 exec 函數(shù)來實(shí)現(xiàn)運(yùn)行另一個(gè)新的程序。而execl函數(shù)是exec族函數(shù)里面的其中一個(gè)員,但它是比較常使用的那個(gè)。
??1、先創(chuàng)建新的程序hello.c文件。
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??2、創(chuàng)建一個(gè)execl.c文件,功能:創(chuàng)建子進(jìn)程,并且將子進(jìn)程繼承的父進(jìn)程的程序替換成新的程序,并運(yùn)行。
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??上圖測試現(xiàn)象可知,execl函數(shù)是可以替換子進(jìn)行的程序,然后執(zhí)行新的程序的。

五、關(guān)于終端上對進(jìn)程的一些指令操作

??指令:ps -aux
??其功能是查看系統(tǒng)進(jìn)程的詳細(xì)信息。

??指令: | grep
??其功能是管道篩選信息。

??指令:kill -9 [pid]
??其功能是殺死,結(jié)束對應(yīng)進(jìn)程。

六、孤兒進(jìn)程

??父進(jìn)程先于子進(jìn)程結(jié)束,也就是意味著,此時(shí)子進(jìn)程變成了一個(gè)“孤兒”,我們把這種進(jìn)程就稱為孤兒進(jìn)程;因?yàn)樽舆M(jìn)程在結(jié)束后需要父進(jìn)程將子進(jìn)程的一些資源釋放掉,而父進(jìn)程先于子進(jìn)程結(jié)束的話,那么系統(tǒng)就會(huì)讓init進(jìn)程接管父進(jìn)程職責(zé),釋放結(jié)束后的子進(jìn)程資源。 在 Linux 系統(tǒng)當(dāng)中,所有的孤兒進(jìn)程都自動(dòng)成為 init 進(jìn)程(進(jìn)程號為 1)的子進(jìn)程, 換言之,某一子進(jìn)程的父進(jìn)程結(jié)束后,該子進(jìn)程調(diào)用 getppid()將返回 1, init 進(jìn)程變成了孤兒進(jìn)程的“養(yǎng)父”。

??孤兒進(jìn)程程序?qū)崿F(xiàn)與測試:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??由上圖測試結(jié)果可知,在紅色框框中,父進(jìn)程還未結(jié)束;在黃色框框中,由于子進(jìn)程sleep阻塞了3秒,父進(jìn)程先于子進(jìn)程結(jié)束了,然后子進(jìn)程的父進(jìn)程(pid=10604)變成了父進(jìn)程(pid=2122),在右邊框框可知,pid:2122是/sbin/upstart其實(shí)就是init進(jìn)程。

七、僵尸進(jìn)程

??進(jìn)程結(jié)束之后,通常需要其父進(jìn)程為其“收尸”,回收子進(jìn)程占用的一些內(nèi)存資源,父進(jìn)程通過調(diào)用wait()(或其變體 waitpid()、 waitid()等)函數(shù)回收子進(jìn)程資源,歸還給系統(tǒng)。
??如果子進(jìn)程先于父進(jìn)程結(jié)束,此時(shí)父進(jìn)程還未來得及給子進(jìn)程“收尸”,那么此時(shí)子進(jìn)程就變成了一個(gè)僵尸進(jìn)程。 子進(jìn)程結(jié)束后其父進(jìn)程并沒有來得及立馬給它“收尸”, 子進(jìn)程處于“曝尸荒野”的狀態(tài),在這么一個(gè)狀態(tài)下,我們就將子進(jìn)程成為僵尸進(jìn)程;至于名字由來,肯定是對電影情節(jié)的一種效仿!
??當(dāng)父進(jìn)程調(diào)用 wait()(或其變體,下文不再強(qiáng)調(diào))為子進(jìn)程“收尸”后,僵尸進(jìn)程就會(huì)被內(nèi)核徹底刪除。另外一種情況,如果父進(jìn)程并沒有調(diào)用 wait()函數(shù)然后就退出了,那么此時(shí) init 進(jìn)程將會(huì)接管它的子進(jìn)程并自動(dòng)調(diào)用 wait(), 故而從系統(tǒng)中移除僵尸進(jìn)程。
??如果父進(jìn)程創(chuàng)建了某一子進(jìn)程,子進(jìn)程已經(jīng)結(jié)束,而父進(jìn)程還在正常運(yùn)行,但父進(jìn)程并未調(diào)用 wait()回收子進(jìn)程,此時(shí)子進(jìn)程變成一個(gè)僵尸進(jìn)程。 首先來說,這樣的程序設(shè)計(jì)是有問題的,如果系統(tǒng)中存在大量的僵尸進(jìn)程,它們勢必會(huì)填滿內(nèi)核進(jìn)程表,從而阻礙新進(jìn)程的創(chuàng)建。需要注意的是,僵尸進(jìn)程是無法通過信號將其殺死的,即使是“一擊必殺”信號 SIGKILL 也無法將其殺死,那么這種情況下,只能殺死僵尸進(jìn)程的父進(jìn)程(或等待其父進(jìn)程終止),這樣 init 進(jìn)程將會(huì)接管這些僵尸進(jìn)程,從而將它們從系統(tǒng)中清理掉!所以,在我們的一個(gè)程序設(shè)計(jì)中,一定要監(jiān)視子進(jìn)程的狀態(tài)變化,如果子進(jìn)程終止了,要調(diào)用 wait()將其回收,避免僵尸進(jìn)程。

??僵尸進(jìn)程程序?qū)崿F(xiàn)與測試:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??通過命令可以查看到子進(jìn)程 10997 依然存在,可以看到它的狀態(tài)欄顯示的是“Z”(zombie,僵尸),表示它是一個(gè)僵尸進(jìn)程。 僵尸進(jìn)程無法被信號殺死,大家可以試試,要么等待其父進(jìn)程終止、要么殺死其父進(jìn)程,讓 init 進(jìn)程來處理,當(dāng)我們殺死其父進(jìn)程之后,僵尸進(jìn)程也會(huì)被隨之清理。

1、監(jiān)視子進(jìn)程

??在很多應(yīng)用程序的設(shè)計(jì)中,父進(jìn)程需要知道子進(jìn)程于何時(shí)被終止,并且需要知道子進(jìn)程的終止?fàn)顟B(tài)信息,是正常終止、還是異常終止亦或者被信號終止等,意味著父進(jìn)程會(huì)對子進(jìn)程進(jìn)行監(jiān)視。而這可以通過系統(tǒng)調(diào)用 wait()以及其它變體來監(jiān)視子進(jìn)程的狀態(tài)改變。

??wait()函數(shù):
??對于許多需要?jiǎng)?chuàng)建子進(jìn)程的進(jìn)程來說,有時(shí)設(shè)計(jì)需要監(jiān)視子進(jìn)程的終止時(shí)間以及終止時(shí)的一些狀態(tài)信息,在某些設(shè)計(jì)需求下這是很有必要的。 系統(tǒng)調(diào)用 wait()可以等待進(jìn)程的任一子進(jìn)程終止,同時(shí)獲取子進(jìn)程的終止?fàn)顟B(tài)信息,其函數(shù)原型如下所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

??使用wait函數(shù)監(jiān)視子進(jìn)程程序?qū)崿F(xiàn)與測試:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??實(shí)驗(yàn)現(xiàn)象可知,父進(jìn)程也是經(jīng)過2秒的等待后才進(jìn)行對子進(jìn)程收尸處理的,說明wait()函數(shù)能起到監(jiān)視和減少子進(jìn)程變成僵尸進(jìn)程發(fā)生。

八、守護(hù)進(jìn)程

1、何為守護(hù)進(jìn)程

??守護(hù)進(jìn)程(Daemon) 也稱為精靈進(jìn)程,是運(yùn)行在后臺的一種特殊進(jìn)程,它獨(dú)立于控制終端并且周期性地執(zhí)行某種任務(wù)或等待處理某些事情的發(fā)生, 主要表現(xiàn)為以下兩個(gè)特點(diǎn):
??? 長期運(yùn)行。 守護(hù)進(jìn)程是一種生存期很長的一種進(jìn)程,它們一般在系統(tǒng)啟動(dòng)時(shí)開始運(yùn)行,除非強(qiáng)行終止,否則直到系統(tǒng)關(guān)機(jī)都會(huì)保持運(yùn)行。 與守護(hù)進(jìn)程相比,普通進(jìn)程都是在用戶登錄或運(yùn)行程序時(shí)創(chuàng)建,在運(yùn)行結(jié)束或用戶注銷時(shí)終止,但守護(hù)進(jìn)程不受用戶登錄注銷的影響,它們將會(huì)一直運(yùn)行著、直到系統(tǒng)關(guān)機(jī)。
??? 與控制終端脫離。 在 Linux 中,系統(tǒng)與用戶交互的界面稱為終端,每一個(gè)從終端開始運(yùn)行的進(jìn)程都會(huì)依附于這個(gè)終端,這是上一小節(jié)給大家介紹的控制終端,也就是會(huì)話的控制終端。當(dāng)控制終端被關(guān)閉的時(shí)候, 該會(huì)話就會(huì)退出, 由控制終端運(yùn)行的所有進(jìn)程都會(huì)被終止, 這使得普通進(jìn)程都是和運(yùn)行該進(jìn)程的終端相綁定的; 但守護(hù)進(jìn)程能突破這種限制,它脫離終端并且在后臺運(yùn)行, 脫離終端的目的是為了避免進(jìn)程在運(yùn)行的過程中的信息在終端顯示并且進(jìn)程也不會(huì)被任何終端所產(chǎn)生的信息所打斷。
??守護(hù)進(jìn)程是一種很有用的進(jìn)程。 Linux 中大多數(shù)服務(wù)器就是用守護(hù)進(jìn)程實(shí)現(xiàn)的,譬如, Internet 服務(wù)器inetd、 Web 服務(wù)器 httpd 等。同時(shí),守護(hù)進(jìn)程完成許多系統(tǒng)任務(wù),譬如作業(yè)規(guī)劃進(jìn)程 crond 等。
??守護(hù)進(jìn)程 Daemon,通常簡稱為 d,一般進(jìn)程名后面帶有 d 就表示它是一個(gè)守護(hù)進(jìn)程。守護(hù)進(jìn)程與終端無任何關(guān)聯(lián),用戶的登錄與注銷與守護(hù)進(jìn)程無關(guān)、不受其影響,守護(hù)進(jìn)程自成進(jìn)程組、自成會(huì)話,即pid=gid=sid。通過命令"ps -ajx"查看系統(tǒng)所有的進(jìn)程,如下所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??TTY 一欄是問號?表示該進(jìn)程沒有控制終端,也就是守護(hù)進(jìn)程,其中 COMMAND 一欄使用中括號[]括起來的表示內(nèi)核線程,這些線程是在內(nèi)核里創(chuàng)建,沒有用戶空間代碼,因此沒有程序文件名和命令行,通常采用 k 開頭的名字,表示 Kernel。

2、編寫守護(hù)進(jìn)程程序

??編寫守護(hù)進(jìn)程一般包含如下幾個(gè)步驟:
??1) 創(chuàng)建子進(jìn)程、終止父進(jìn)程
??父進(jìn)程調(diào)用 fork()創(chuàng)建子進(jìn)程,然后父進(jìn)程使用 exit()退出,這樣做實(shí)現(xiàn)了下面幾點(diǎn)。第一,如果該守護(hù)進(jìn)程是作為一條簡單地 shell 命令啟動(dòng),那么父進(jìn)程終止會(huì)讓 shell 認(rèn)為這條命令已經(jīng)執(zhí)行完畢。第二,雖然子進(jìn)程繼承了父進(jìn)程的進(jìn)程ID,但它有自己獨(dú)立的進(jìn)程ID,這保證了子進(jìn)程不是一個(gè)進(jìn)程組的組長進(jìn)程,這是下面將要調(diào)用 setsid 函數(shù)的先決條件!
??2) 子進(jìn)程調(diào)用 setsid 創(chuàng)建會(huì)話
??這步是關(guān)鍵,由于之前子進(jìn)程并不是進(jìn)程組的組長進(jìn)程,所以調(diào)用 setsid()會(huì)使得子進(jìn)程創(chuàng)建一個(gè)新的會(huì)話,子進(jìn)程成為新會(huì)話的首領(lǐng)進(jìn)程,同樣也創(chuàng)建了新的進(jìn)程組、子進(jìn)程成為組長進(jìn)程,此時(shí)創(chuàng)建的會(huì)話將沒有控制終端。 所以這里調(diào)用 setsid 有三個(gè)作用:讓子進(jìn)程擺脫原會(huì)話的控制、讓子進(jìn)程擺脫原進(jìn)程組的控制和讓子進(jìn)程擺脫原控制終端的控制。在調(diào)用 fork 函數(shù)時(shí),子進(jìn)程繼承了父進(jìn)程的會(huì)話、進(jìn)程組、控制終端等,雖然父進(jìn)程退出了,但原先的會(huì)話期、進(jìn)程組、控制終端等并沒有改變,因此,那還不是真正意義上使兩者獨(dú)立開來。 setsid 函數(shù)能夠使子進(jìn)程完全獨(dú)立出來,從而脫離所有其他進(jìn)程的控制。
??3) 將工作目錄更改為根目錄
??子進(jìn)程是繼承了父進(jìn)程的當(dāng)前工作目錄,由于在進(jìn)程運(yùn)行中,當(dāng)前目錄所在的文件系統(tǒng)是不能卸載的,這對以后使用會(huì)造成很多的麻煩。因此通常的做法是讓“/”作為守護(hù)進(jìn)程的當(dāng)前目錄,當(dāng)然也可以指定其它目錄來作為守護(hù)進(jìn)程的工作目錄。
??4) 重設(shè)文件權(quán)限掩碼 umask
??文件權(quán)限掩碼 umask 用于對新建文件的權(quán)限位進(jìn)行屏蔽。由于使用 fork 函數(shù)新建的子進(jìn)程繼承了父進(jìn)程的文件權(quán)限掩碼,這就給子進(jìn)程使用文件帶來了諸多的麻煩。因此, 把文件權(quán)限掩碼設(shè)置為 0, 確保子進(jìn)程有最大操作權(quán)限、這樣可以大大增強(qiáng)該守護(hù)進(jìn)程的靈活性。設(shè)置文件權(quán)限掩碼的函數(shù)是 umask,通常的使用方法為 umask(0)。
??5) 關(guān)閉不再需要的文件描述符
??子進(jìn)程繼承了父進(jìn)程的所有文件描述符, 這些被打開的文件可能永遠(yuǎn)不會(huì)被守護(hù)進(jìn)程(此時(shí)守護(hù)進(jìn)程指的就是子進(jìn)程,父進(jìn)程退出、子進(jìn)程成為守護(hù)進(jìn)程) 讀或?qū)?,但它們一樣消耗系統(tǒng)資源,可能導(dǎo)致所在的文件系統(tǒng)無法卸載,所以必須關(guān)閉這些文件, 這使得守護(hù)進(jìn)程不再持有從其父進(jìn)程繼承過來的任何文件描述符。
??6) 將文件描述符號為 0、 1、 2 定位到/dev/null
??將守護(hù)進(jìn)程的標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出以及標(biāo)準(zhǔn)錯(cuò)誤重定向到/dev/null,這使得守護(hù)進(jìn)程的輸出無處顯示、也無處從交互式用戶那里接收輸入。
??7) 其它:忽略 SIGCHLD 信號
??處理 SIGCHLD 信號不是必須的, 但對于某些進(jìn)程,特別是并發(fā)服務(wù)器進(jìn)程往往是特別重要的,服務(wù)器進(jìn)程在接收到客戶端請求時(shí)會(huì)創(chuàng)建子進(jìn)程去處理該請求,如果子進(jìn)程結(jié)束之后,父進(jìn)程沒有去 wait 回收子進(jìn)程,則子進(jìn)程將成為僵尸進(jìn)程;如果父進(jìn)程 wait 等待子進(jìn)程退出,將又會(huì)增加父進(jìn)程的負(fù)擔(dān)、也就是增加服務(wù)器的負(fù)擔(dān),影響服務(wù)器進(jìn)程的并發(fā)性能,在 Linux 下,可以將 SIGCHLD 信號的處理方式設(shè)置為SIG_IGN,也就是忽略該信號,可讓內(nèi)核將僵尸進(jìn)程轉(zhuǎn)交給 init 進(jìn)程去處理,這樣既不會(huì)產(chǎn)生僵尸進(jìn)程、又省去了服務(wù)器進(jìn)程回收子進(jìn)程所占用的時(shí)間。
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

??從上圖可知, daemon進(jìn)程成為了一個(gè)守護(hù)進(jìn)程,與控制臺脫離,當(dāng)關(guān)閉當(dāng)前控制終端時(shí),daemon進(jìn)程并不會(huì)受到影響,依然會(huì)正常繼續(xù)運(yùn)行;
??守護(hù)進(jìn)程可以通過終端命令行啟動(dòng),但通常它們是由系統(tǒng)初始化腳本進(jìn)行啟動(dòng),譬如/etc/rc*或/etc/init.d/*等。

補(bǔ)充知識點(diǎn):
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

九、進(jìn)程間的通信方法實(shí)現(xiàn)

1、管道通信

①無名管道通信

??pipe無名管道通信只能作用在有親緣關(guān)系的進(jìn)程之間通信,詳情如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??pipe是一種單向數(shù)據(jù)傳輸?shù)墓艿?,其參?shù)pipefd[2]是個(gè)整形數(shù)組,而pipefd[0]和pipefd[1]分別是創(chuàng)建的讀管道的文件描述符和寫管道的文件描述符。

??使用pipe函數(shù)實(shí)現(xiàn)父進(jìn)程與子進(jìn)程間的通信及測試:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??從上圖可知,當(dāng)子進(jìn)程讀管道數(shù)據(jù)時(shí),如果管道沒有數(shù)據(jù)就會(huì)一直阻塞。只有管道有數(shù)據(jù)可讀,子進(jìn)程才會(huì)通,如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??在父進(jìn)程中向管道寫入數(shù)據(jù),然后子進(jìn)程向管道讀取數(shù)據(jù)。

②有名管道通信

??mkfifo有名管道通信可以作用在無親緣關(guān)系的進(jìn)程之間通信,詳情如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??mkfifo其實(shí)就是創(chuàng)建了一個(gè)實(shí)實(shí)在在的fifo文件,然后進(jìn)程間的通信就是通過對創(chuàng)建的fifo文件進(jìn)行操作,其fifo文件和塊設(shè)備文件一樣,都是不占用字節(jié)的,如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

??使用mkfifo函數(shù)實(shí)現(xiàn)兩個(gè)無親緣關(guān)系的進(jìn)程間的通信及測試:
??讀fifo數(shù)據(jù)的進(jìn)程程序:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??寫fifo數(shù)據(jù)的進(jìn)程程序:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??現(xiàn)象:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

2、信號通信

??信號的基本概念:信號是事件發(fā)生時(shí)對進(jìn)程的通知機(jī)制,也可以把它稱為軟件中斷。信號與硬件中斷的相似之處在于能夠打斷程序當(dāng)前執(zhí)行的正常流程, 其實(shí)是在軟件層次上對中斷機(jī)制的一種模擬。 大多數(shù)情況下,是無法預(yù)測信號達(dá)到的準(zhǔn)確時(shí)間,所以,信號提供了一種處理異步事件的方法。

信號的目的是用來通信的

??一個(gè)具有合適權(quán)限的進(jìn)程能夠向另一個(gè)進(jìn)程發(fā)送信號,信號的這一用法可作為一種同步技術(shù),甚至是進(jìn)程間通信(IPC)的原始形式。 信號可以由“誰”發(fā)出呢? 以下列舉的很多情況均可以產(chǎn)生信號:
??? 硬件發(fā)生異常,即硬件檢測到錯(cuò)誤條件并通知內(nèi)核,隨即再由內(nèi)核發(fā)送相應(yīng)的信號給相關(guān)進(jìn)程。硬件檢測到異常的例子包括執(zhí)行一條異常的機(jī)器語言指令,諸如,除數(shù)為 0、數(shù)組訪問越界導(dǎo)致引用了無法訪問的內(nèi)存區(qū)域等,這些異常情況都會(huì)被硬件檢測到,并通知內(nèi)核、然后內(nèi)核為該異常情況發(fā)生時(shí)正在運(yùn)行的進(jìn)程發(fā)送適當(dāng)?shù)男盘栆酝ㄖM(jìn)程。
??? 用于在終端下輸入了能夠產(chǎn)生信號的特殊字符。 譬如在終端上按下 CTRL + C 組合按鍵可以產(chǎn)生中斷信號(SIGINT),通過這個(gè)方法可以終止在前臺運(yùn)行的進(jìn)程;按下 CTRL + Z 組合按鍵可以產(chǎn)生暫停信號(SIGCONT),通過這個(gè)方法可以暫停當(dāng)前前臺運(yùn)行的進(jìn)程。
??? 進(jìn)程調(diào)用 kill()系統(tǒng)調(diào)用可將任意信號發(fā)送給另一個(gè)進(jìn)程或進(jìn)程組。 當(dāng)然對此是有所限制的,接收信號的進(jìn)程和發(fā)送信號的進(jìn)程的所有者必須相同,亦或者發(fā)送信號的進(jìn)程的所有者是 root 超級用戶。
??? 用戶可以通過 kill 命令將信號發(fā)送給其它進(jìn)程。 kill 命令想必大家都會(huì)使用,通常我們會(huì)通過 kill命令來“殺死”(終止)一個(gè)進(jìn)程,譬如在終端下執(zhí)行"kill -9 xxx"來殺死 PID 為 xxx 的進(jìn)程。 kill命令其內(nèi)部的實(shí)現(xiàn)原理便是通過 kill()系統(tǒng)調(diào)用來完成的。
??? 發(fā)生了軟件事件,即當(dāng)檢測到某種軟件條件已經(jīng)發(fā)生。 這里指的不是硬件產(chǎn)生的條件(如除數(shù)為 0、引用無法訪問的內(nèi)存區(qū)域等),而是軟件的觸發(fā)條件、觸發(fā)了某種軟件條件(進(jìn)程所設(shè)置的定時(shí)器已經(jīng)超時(shí)、進(jìn)程執(zhí)行的 CPU 時(shí)間超限、進(jìn)程的某個(gè)子進(jìn)程退出等等情況)。
??進(jìn)程同樣也可以向自身發(fā)送信號,然而發(fā)送給進(jìn)程的諸多信號中,大多數(shù)都是來自于內(nèi)核。
??以上便是可以產(chǎn)生信號的多種不同的條件,總的來看,信號的目的都是用于通信的,當(dāng)發(fā)生某種情況下,通過信號將情況“告知”相應(yīng)的進(jìn)程,從而達(dá)到同步、通信的目的。

信號由誰處理、怎么處理

??信號通常是發(fā)送給對應(yīng)的進(jìn)程,當(dāng)信號到達(dá)后, 該進(jìn)程需要做出相應(yīng)的處理措施,通常進(jìn)程會(huì)視具體信號執(zhí)行以下操作之一:
??? 忽略信號。也就是說,當(dāng)信號到達(dá)進(jìn)程后,該進(jìn)程并不會(huì)去理會(huì)它、直接忽略,就好像是沒有出該信號,信號對該進(jìn)程不會(huì)產(chǎn)生任何影響。事實(shí)上,大多數(shù)信號都可以使用這種方式進(jìn)行處理,但有兩種信號卻決不能被忽略,它們是 SIGKILL 和 SIGSTOP,這兩種信號不能被忽略的原因是:它們向內(nèi)核和超級用戶提供了使進(jìn)程終止或停止的可靠方法。另外,如果忽略某些由硬件異常產(chǎn)生的信號,則進(jìn)程的運(yùn)行行為是未定義的。
??? 捕獲信號。 當(dāng)信號到達(dá)進(jìn)程后,執(zhí)行預(yù)先綁定好的信號處理函數(shù)。為了做到這一點(diǎn),要通知內(nèi)核在某種信號發(fā)生時(shí),執(zhí)行用戶自定義的處理函數(shù),該處理函數(shù)中將會(huì)對該信號事件作出相應(yīng)的處理,Linux 系統(tǒng)提供了 signal()系統(tǒng)調(diào)用可用于注冊信號的處理函數(shù)。
??? 執(zhí)行系統(tǒng)默認(rèn)操作。 進(jìn)程不對該信號事件作出處理,而是交由系統(tǒng)進(jìn)行處理,每一種信號都會(huì)有其對應(yīng)的系統(tǒng)默認(rèn)的處理方式。需要注意的是,對大多數(shù)信號來說,系統(tǒng)默認(rèn)的處理方式就是終止該進(jìn)程。

信號是異步的

??信號是異步事件的經(jīng)典實(shí)例,產(chǎn)生信號的事件對進(jìn)程而言是隨機(jī)出現(xiàn)的,進(jìn)程無法預(yù)測該事件產(chǎn)生的準(zhǔn)確時(shí)間,進(jìn)程不能夠通過簡單地測試一個(gè)變量或使用系統(tǒng)調(diào)用來判斷是否產(chǎn)生了一個(gè)信號,這就如同硬件中斷事件,程序是無法得知中斷事件產(chǎn)生的具體時(shí)間,只有當(dāng)產(chǎn)生中斷事件時(shí),才會(huì)告知程序、然后打斷當(dāng)前程序的正常執(zhí)行流程、跳轉(zhuǎn)去執(zhí)行中斷服務(wù)函數(shù),這就是異步處理方式。


??信號本質(zhì)上是 int 類型數(shù)字編號,這些信號在<signum.h>頭文件中定義, 每個(gè)信號都是以 SIGxxx 開頭,這里就自己去查了。


①信號的分類

Ⅰ、可靠信號與不可靠信號:

??不可靠信號主要指的是進(jìn)程可能對信號做出錯(cuò)誤的反應(yīng)以及信號可能丟失(處理信號時(shí)又來了新的信號,則導(dǎo)致信號丟失)。
??在 Linux 系統(tǒng)下使用"kill -l"命令可查看到所有信號,如下所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??括號" ) "前面的數(shù)字對應(yīng)該信號的編號,編號 1~31 所對應(yīng)的是不可靠信號,編號 34~64 對應(yīng)的是
可靠信號,從圖中可知,可靠信號并沒有一個(gè)具體對應(yīng)的名字,而是使用了 SIGRTMIN+N 或 SIGRTMAXN 的方式來表示。

Ⅱ、實(shí)時(shí)信號與非實(shí)時(shí)信號:

??實(shí)時(shí)信號與非實(shí)時(shí)信號其實(shí)是從時(shí)間關(guān)系上進(jìn)行的分類,與可靠信號與不可靠信號是相互對應(yīng)的, 非實(shí)時(shí)信號都不支持排隊(duì),都是不可靠信號;實(shí)時(shí)信號都支持排隊(duì),都是可靠信號。 實(shí)時(shí)信號保證了發(fā)送的多個(gè)信號都能被接收, 實(shí)時(shí)信號是 POSIX 標(biāo)準(zhǔn)的一部分,可用于應(yīng)用進(jìn)程。

②信號的發(fā)送函數(shù)及使用測試實(shí)驗(yàn)

Ⅰ、raise()函數(shù)

??可以在終端中敲man 3 raise可知raise函數(shù)的功能,如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??由上圖可知,raise(sig)等價(jià)于kill(getpid(), sig),也就是說其功能就是自己給自己發(fā)送信號(實(shí)質(zhì)是先將信號和pid號發(fā)給內(nèi)核,內(nèi)核再發(fā)送該信號給對應(yīng)的pid進(jìn)程或直接處理)。
??這里我做一個(gè)簡單自己殺死自己的實(shí)驗(yàn),如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

Ⅱ、kill()函數(shù)

??這里不過多介紹該函數(shù)了,可以在man手冊查詢。
??這里我做一個(gè)簡單 “進(jìn)程kill” 殺死手動(dòng)指定的 “進(jìn)程a” 的實(shí)驗(yàn),如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

Ⅱ、alarm()函數(shù)

??這里不過多介紹該函數(shù)了,可以在man手冊查詢。
??這里我做一個(gè)簡單鬧鐘定時(shí)程序,當(dāng)時(shí)間到了發(fā)出鬧鐘時(shí)間就終止程序的實(shí)驗(yàn),如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

③信號的接收函數(shù)及使用測試實(shí)驗(yàn)

Ⅰ、pause()函數(shù)

??pause()系統(tǒng)調(diào)用可以使得進(jìn)程暫停運(yùn)行、進(jìn)入休眠狀態(tài),直到進(jìn)程捕獲到一個(gè)信號為止,詳細(xì)信息可以可以在man手冊查詢。
??這里我做一個(gè)簡單鬧鐘定時(shí)使程序退出pause狀態(tài),這次鬧鐘程序不是用默認(rèn)的信號處理函數(shù),當(dāng)時(shí)間到了發(fā)出鬧鐘時(shí)間就觸發(fā)pause函數(shù),讓程序繼續(xù)往下走,如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

④信號的處理函數(shù)及使用測試實(shí)驗(yàn)

Ⅰ、signal()函數(shù)

??當(dāng)進(jìn)程接收到內(nèi)核或用戶發(fā)送過來的信號之后,根據(jù)具體信號可以采取不同的處理方式:忽略信號、捕獲信號或者執(zhí)行系統(tǒng)默認(rèn)操作。
??忽略信號:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??系統(tǒng)默認(rèn):
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??捕獲信號:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

3、共享內(nèi)存

①共享內(nèi)存的概念

??共享內(nèi)存就是映射一段能被其它進(jìn)程所訪問的內(nèi)存, 這段共享內(nèi)存由一個(gè)進(jìn)程創(chuàng)建, 但其它的多個(gè)進(jìn)程都可以訪問, 使得多個(gè)進(jìn)程可以訪問同一塊內(nèi)存空間。共享內(nèi)存是最快的 IPC 方式, 它是針對其它進(jìn)程間通信方式運(yùn)行效率低而專門設(shè)計(jì)的, 它往往與其它通信機(jī)制, 譬如結(jié)合信號量來使用, 以實(shí)現(xiàn)進(jìn)程間的同步和通信。

②shmget函數(shù)和ftok函數(shù)

Ⅰ、shmget函數(shù)

??這里我截取了man手冊的描述,它是一個(gè)向系統(tǒng)申請分配一個(gè)共享內(nèi)存空間的函數(shù),如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
注意:參數(shù)key值除了可以使用文檔描述的 IPC_PRIVATE 這個(gè)宏外,還可以使用ftok函數(shù)獲取這個(gè)key值

Ⅱ、ftok函數(shù)

Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

Ⅲ、shmat、shmdt、shmctl函數(shù)

??上述說過,使用shmget函數(shù)申請分配共享內(nèi)存成功后,它會(huì)返回共享內(nèi)存標(biāo)識符,它和文件標(biāo)識符是類似的,但是這個(gè)不便于我們?nèi)ゲ僮鬟@個(gè)共享內(nèi)存,所以在Linux應(yīng)用中經(jīng)常會(huì)使用共享內(nèi)存映射到進(jìn)程地址上,方便開發(fā)者直接對共享內(nèi)存進(jìn)行讀寫操作。
??shmat、shmdt、shmctl函數(shù)分別是創(chuàng)建共享內(nèi)存映射、刪除共享內(nèi)存映射(但不會(huì)刪除內(nèi)核中的共享內(nèi)存對象)、操作共享內(nèi)存對象。

Ⅳ、使用shmget函數(shù)實(shí)現(xiàn)以共享內(nèi)存方式的父子進(jìn)程間的通信及測試實(shí)驗(yàn)

??我們先了解一下,使用系統(tǒng)自帶的密鑰IPC_PRIVATE和使用ftok函數(shù)自己獲取的密鑰 向系統(tǒng)申請分配共享內(nèi)存的區(qū)別,圖下兩張圖的實(shí)驗(yàn)所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒


Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
??由上面兩張實(shí)驗(yàn)結(jié)果對比可知,使用系統(tǒng)自帶的密鑰IPC_PRIVATE和使用ftok函數(shù)自己獲取的密鑰 向系統(tǒng)申請分配共享內(nèi)存的區(qū)別前者共享內(nèi)存描述符是為0的,而后者的共享描述符是不為0的。
??好,有了上面的了解,正式做要實(shí)現(xiàn)的實(shí)驗(yàn),如下圖所示:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

4、消息隊(duì)列

①消息隊(duì)列的概述

??消息隊(duì)列是消息的鏈表, 存放在內(nèi)核中并由消息隊(duì)列標(biāo)識符標(biāo)識, 消息隊(duì)列克服了信號傳遞信息少、 管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等缺陷。 消息隊(duì)列包括 POSIX 消息隊(duì)列和 System V 消息隊(duì)列。

??而 POSIX 消息隊(duì)列和 System V 消息隊(duì)列異同點(diǎn):

目的不同:POSIX 消息隊(duì)列主要用于進(jìn)程間通信,而 System V 消息隊(duì)列可以進(jìn)行進(jìn)程間和線程間的通信。
接口不同:POSIX 消息隊(duì)列使用 mq_open(), mq_send(), mq_receive()等函數(shù)進(jìn)行操作,而 System V 消息隊(duì)列主要使用msgget(), msgsnd(), msgrcv()等函數(shù)進(jìn)行操作。
大小限制不同:POSIX 消息隊(duì)列沒有固定的消息大小限制,但是 System V 消息隊(duì)列有固定的消息大小限制。
使用方式不同:POSIX 消息隊(duì)列的使用方式更為靈活,可以使用文件描述符來操作消息隊(duì)列;而 System V 消息隊(duì)列需要通過>鍵值來找到消息隊(duì)列。
發(fā)送和接收消息的方式不同:POSIX 消息隊(duì)列可以設(shè)置優(yōu)先級,支持非阻塞方式和阻塞方式;而 System V 消息隊(duì)列僅支持阻
塞方式,且不支持消息的優(yōu)先級。
刪除消息隊(duì)列方式不同:POSIX 消息隊(duì)列可以使用 mq_close()和mq_unlink()函數(shù)刪除消息隊(duì)列,而刪除 System V 消息隊(duì)列需>要使用 msgctl()函數(shù)。
相同點(diǎn):都是進(jìn)程通信的一種手段。都可以實(shí)現(xiàn)消息的發(fā)送和接收,保證進(jìn)程間的異步通信。都可以使用信號量機(jī)制實(shí)現(xiàn)消息的>同步和互斥。

??消息隊(duì)列是 UNIX 下不同進(jìn)程之間實(shí)現(xiàn)共享資源的一種機(jī)制, UNIX 允許不同進(jìn)程將格式化的數(shù)據(jù)流以消息隊(duì)列形式發(fā)送給任意進(jìn)程, 有足夠權(quán)限的進(jìn)程可以向隊(duì)列中添加消息,被賦予讀權(quán)限的進(jìn)程則可以讀走隊(duì)列中的消息。

②使用消息隊(duì)列實(shí)現(xiàn)兩個(gè)無情緣關(guān)系之間的進(jìn)程通信

Ⅰ、關(guān)于消息隊(duì)列創(chuàng)建時(shí)用的key值的知識

Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

Ⅱ、實(shí)現(xiàn)實(shí)驗(yàn)及測試

程序:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒
結(jié)果:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

5、信號量

①信號量的概述

??信號量是一個(gè)計(jì)數(shù)器, 與其它進(jìn)程間通信方式不大相同, 它主要用于保護(hù)臨界資源,控制多個(gè)進(jìn)程間或一個(gè)進(jìn)程內(nèi)的多個(gè)線程間對共享資源的訪問, 相當(dāng)于內(nèi)存中的標(biāo)志,進(jìn)程可以根據(jù)它判定是否能夠訪問某些共享資源,同時(shí),進(jìn)程也可以修改該標(biāo)志, 除了用于共享資源的訪問控制外,還可用于進(jìn)程同步。
??它常作為一種鎖機(jī)制, 防止某進(jìn)程在訪問資源時(shí)其它進(jìn)程也訪問該資源, 因此, 主要作為進(jìn)程間以及同一個(gè)進(jìn)程內(nèi)不同線程之間的同步手段。 Linux 提供了一組精心設(shè)計(jì)的信號量接口來對信號量進(jìn)行操作,它們聲明在頭文件 sys/sem.h 中。

②使用信號量實(shí)現(xiàn)進(jìn)程間的通信

Ⅰ、使用sleep阻塞方式,使父進(jìn)程先于子進(jìn)程運(yùn)行

Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒

Ⅱ、在上一個(gè)實(shí)驗(yàn)基礎(chǔ)上,使用信號量的阻塞方式,使子進(jìn)程先于父進(jìn)程運(yùn)行

semaphore.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/wait.h>

//信號量操作函數(shù)semctl中參數(shù)2聯(lián)合體
union semun {
    int              val;    /* Value for SETVAL */
    struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
    unsigned short  *array;  /* Array for GETALL, SETALL */
    struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                           (Linux-specific) */
};

int main(int argc,  char *argv[])
{
    pid_t pid;  //進(jìn)程號
    key_t key;  //密鑰key
    int semid; //信號量集標(biāo)識符
    union semun my_sem_union;    //聯(lián)合體,目的是初始化信號量的值
    struct sembuf sop;  //信號量結(jié)構(gòu)體數(shù)組,semop函數(shù)使用
    int ret;

    key = ftok("./my_keyfile", 24678);    //獲取key值
    if(key == -1) {
        printf("ftok error\n");
        exit(-1);
    } else {
        printf("ftok ok,the key is %#X\n",key);
    }

    /*  向系統(tǒng)申請創(chuàng)建信號量,參數(shù)1:密鑰key
        參數(shù)2:信號量個(gè)數(shù)      參數(shù)3:權(quán)限   */
    semid = semget(key, 1, 0777 | IPC_CREAT);
    if(semid == -1) {
        printf("semget error\n");
        exit(-1);
    } else {
        printf("semid is %d\n", semid);
    }

    //初始化信號量
    my_sem_union.val = 0;   //信號量值為0
    ret = semctl(semid,0,SETVAL,my_sem_union);    //初始化第0個(gè)信號量的值
    if(ret == -1) {
        printf("semctl error\n");
        exit(-1);
    }

    pid = fork();   //創(chuàng)建子進(jìn)程
    if(pid == -1) {
        printf("fork failed\n");
        exit(-1);
    }

    //父進(jìn)程
    if(pid > 0) {
        int status; //子進(jìn)程結(jié)束狀態(tài)
        sop.sem_num = 0;    //信號量編號為0
        sop.sem_op = -1;    //分配資源,-1操作
        sop.sem_flg = 0;     //阻塞操作
        ret = semop(semid, &sop, 1);    //參數(shù)3:1個(gè)信號量集
        if(ret == -1) {
            printf("semop failed\n");
            exit(-1);
        }
        printf("I am father\n");
        wait(&status);  //監(jiān)視子進(jìn)程,等待退出
    }

    //子進(jìn)程
    if(pid == 0) {
        sleep(2);   //休眠2秒,讓父進(jìn)程先運(yùn)行
        sop.sem_num = 0;    //信號量編號為0
        sop.sem_op = 1;    //分配資源,-1操作
        sop.sem_flg = 0;     //阻塞操作
        ret = semop(semid, &sop, 1);    //參數(shù)3:1個(gè)信號量集
        printf("I am son\n");
    }

    exit(0);
}

實(shí)驗(yàn)現(xiàn)象:
Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒文章來源地址http://www.zghlxwxcb.cn/news/detail-423818.html

到了這里,關(guān)于Linux應(yīng)用程序開發(fā):進(jìn)程的一些事兒的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Linux設(shè)備模型統(tǒng)一:橋接硬件多樣性與應(yīng)用程序開發(fā)的關(guān)鍵

    Linux設(shè)備模型統(tǒng)一:橋接硬件多樣性與應(yīng)用程序開發(fā)的關(guān)鍵

    在Linux的宏大世界中,各種各樣的硬件設(shè)備如星辰般繁多。從常見的USB設(shè)備到復(fù)雜的網(wǎng)絡(luò)接口卡,從嵌入式設(shè)備到強(qiáng)大的服務(wù)器,Linux需要在這些差異極大的硬件上運(yùn)行。這就引出了一個(gè)問題:Linux是如何統(tǒng)一這些不同硬件的設(shè)備模型的呢?本文將探討Linux是如何針對不同的硬

    2024年04月10日
    瀏覽(18)
  • Electron打包的桌面應(yīng)用程序,運(yùn)行中程序黑屏、白屏等渲染進(jìn)程崩潰問題解決

    使用 Electron 打包 web 項(xiàng)目為桌面應(yīng)用程序,由于運(yùn)行環(huán)境的硬件條件或其他一些原因,導(dǎo)致程序運(yùn)行過程中黑屏、白屏、崩潰。 2.1 依賴版本: electron : v8.2.1 electron-log : v4.1.1 electron-packager : v14.2.1 2.2 運(yùn)行環(huán)境 win7 x86 2.3 分析過程 2.3.1 排除 程序本身運(yùn)行不會(huì)“白屏”,但運(yùn)行

    2024年02月07日
    瀏覽(57)
  • C# WPF應(yīng)用使用visual studio的安裝程序類的一些坑

    C# WPF應(yīng)用使用visual studio的安裝程序類的一些坑

    否則會(huì)出現(xiàn)命名空間System.Configuration不存在Install的報(bào)錯(cuò) ? var s = Context.Parameters[\\\"assemblypath\\\"].ToString() 這個(gè)里面是當(dāng)前文件的路徑,所以需要?jiǎng)h除掉文件的名字才能獲取目錄路徑 var dir = s.Substring(0, s.LastIndexOf(\\\"\\\\\\\") + 1)

    2024年02月12日
    瀏覽(26)
  • Building AI-Copilot:構(gòu)建 LLM 支持的生成應(yīng)用程序的一些經(jīng)驗(yàn)教訓(xùn)和模式

    我們正在構(gòu)建一個(gè)用于產(chǎn)品策略和生成創(chuàng)意的實(shí)驗(yàn)性人工智能副駕駛,名為“Boba”。一路上,我們學(xué)到了一些關(guān)于如何構(gòu)建此類應(yīng)用程序的有用經(jīng)驗(yàn),我們已經(jīng)根據(jù)模式制定了這些應(yīng)用程序。這些模式允許應(yīng)用程序幫助用戶更有效地與大語言模型 (LLM) 交互,編排提示以獲得

    2024年02月14日
    瀏覽(21)
  • CoreDX DDS應(yīng)用開發(fā)指南(5)開發(fā)發(fā)布應(yīng)用程序

    ????????創(chuàng)建發(fā)布應(yīng)用程序的步驟如下: 創(chuàng)建或獲取應(yīng)用程序數(shù)據(jù)的DDL文件。 使用DDL編譯器編譯DDL文件。類型特定的支持和DataWriter是編譯DDL的結(jié)果。 編寫發(fā)布應(yīng)用程序 編譯發(fā)布應(yīng)用程序 ????????啟用DDS的應(yīng)用程序本質(zhì)上是以數(shù)據(jù)為中心data-centric的。為了使這些以數(shù)

    2024年02月08日
    瀏覽(22)
  • Flutter中的Web應(yīng)用程序開發(fā):構(gòu)建現(xiàn)代Web應(yīng)用程序

    作者:禪與計(jì)算機(jī)程序設(shè)計(jì)藝術(shù) 作為人工智能專家,程序員和軟件架構(gòu)師,CTO,我今天將為大家分享有關(guān) Flutter 中 Web 應(yīng)用程序開發(fā)的見解。在這篇文章中,我們將深入探討 Flutter Web 應(yīng)用程序的開發(fā)過程、技術(shù)原理以及最佳實(shí)踐。 引言 隨著移動(dòng)設(shè)備的普及,Web 應(yīng)用程序在全

    2024年02月12日
    瀏覽(33)
  • Linux和windows進(jìn)程同步與線程同步那些事兒(五):Linux下進(jìn)程同步

    Linux和windows進(jìn)程同步與線程同步那些事兒(一) Linux和windows進(jìn)程同步與線程同步那些事兒(二): windows線程同步詳解示例 Linux和windows進(jìn)程同步與線程同步那些事兒(三): Linux線程同步詳解示例 Linux和windows進(jìn)程同步與線程同步那些事兒(四):windows 下進(jìn)程同步 Linux和wi

    2024年02月02日
    瀏覽(27)
  • 開發(fā)GPT的應(yīng)用程序流程

    開發(fā)GPT的應(yīng)用程序流程

    開發(fā)一個(gè)基于GPT的應(yīng)用程序(GPT APP)涉及到與GPT模型的集成,用戶界面設(shè)計(jì),以及應(yīng)用程序的功能實(shí)現(xiàn)。以下是一個(gè)一般的開發(fā)流程,希望對大家有所幫助。北京木奇移動(dòng)技術(shù)有限公司,專業(yè)的軟件外包開發(fā)公司,歡迎交流合作。 明確目標(biāo)和用例: 定義您的GPT應(yīng)用的目標(biāo)和

    2024年01月19日
    瀏覽(27)
  • 《Qt開發(fā)》MDI應(yīng)用程序

    《Qt開發(fā)》MDI應(yīng)用程序

    實(shí)現(xiàn)多個(gè)子窗體的自定義布局(自定義子窗體尺寸和位置)、平鋪布局(titleSubWindows)和分頁模式(QMdi::TabbedView)。 運(yùn)行效果圖 初始布局(自定義布局) 平鋪布局 多頁模式 實(shí)現(xiàn)過程 1. 創(chuàng)建項(xiàng)目MdiFirstDemo,并創(chuàng)建3個(gè)子窗體,分別為FirstSubWindow、SecondSubWindow和ThirdSubWindow。

    2024年01月16日
    瀏覽(85)
  • 桌面應(yīng)用程序開發(fā)攻略(初步了解)

    ????????桌面應(yīng)用開發(fā) 是指為桌面計(jì)算機(jī)或其他類似設(shè)備(如服務(wù)器)開發(fā)軟件應(yīng)用程序的過程。桌面應(yīng)用通常是獨(dú)立于瀏覽器運(yùn)行的,并且可以在操作系統(tǒng)的桌面或應(yīng)用程序菜單中找到。桌面應(yīng)用可以使用各種編程語言開發(fā),包括C++、Java、C#和Python等。桌面應(yīng)用的開發(fā)

    2024年02月09日
    瀏覽(21)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包