代碼段 |
數(shù)據(jù)段 |
堆棧段 |
代碼段是存放了程序代碼的數(shù)據(jù),假如機(jī)器中有數(shù)個(gè)進(jìn)程運(yùn)行相同的一個(gè)程序,那么它們就可以使用同一個(gè)代碼段。而數(shù)據(jù)段則存放程序的全局變量、常數(shù)及動(dòng)態(tài)數(shù)據(jù)分配的數(shù)據(jù)空間。堆棧段存放的就是子進(jìn)程的返回地址、子程序的參數(shù)及程序的局部變量。堆棧段包含在進(jìn)程控制塊PCB(Process Control Block)中。PCB處于進(jìn)程核心堆棧的底部,不需要額外分配空間。
四.進(jìn)程狀態(tài)
現(xiàn)在我們來看看,進(jìn)程在生存周期中的各種狀態(tài)及狀態(tài)的轉(zhuǎn)換。下面是Linux系統(tǒng)的進(jìn)程狀態(tài)模型的各種狀態(tài)。
現(xiàn)在我們從進(jìn)程的創(chuàng)建到退出來看看進(jìn)程的狀態(tài)轉(zhuǎn)化。需要說明的是,進(jìn)程在它的生命周期里并不一定要經(jīng)歷所有狀態(tài)。
五.Linux進(jìn)程的創(chuàng)建
fork函數(shù)在Linux下產(chǎn)生新的進(jìn)程的系統(tǒng)調(diào)用,這個(gè)函數(shù)名是英文中“分叉”的意思。為什么取這個(gè)名字呢? 因?yàn)橐粋€(gè)進(jìn)程在運(yùn)行中,如果使用了fork,就產(chǎn)生了另一個(gè)進(jìn)程,于是進(jìn)程就“分叉”了,所以這個(gè)名字取得很形象。fork的語法如下所示:
在Linux網(wǎng)絡(luò)編程中經(jīng)常用到fork()系統(tǒng)調(diào)用。例如在一個(gè)客戶機(jī)/Web服務(wù)器構(gòu)建的網(wǎng)絡(luò)環(huán)境中,Web服務(wù)器往往可以滿足許多客戶端的請(qǐng)求。如果一個(gè)客戶機(jī)要訪問Web服務(wù)器,需要發(fā)送一個(gè)請(qǐng)求,此時(shí)由服務(wù)器生成一個(gè)父進(jìn)程,然后父進(jìn)程通過fork()系統(tǒng)調(diào)用產(chǎn)生一個(gè)子進(jìn)程,此時(shí)客戶機(jī)的請(qǐng)求由子進(jìn)程完成。父進(jìn)程可以再度回到等待狀態(tài)不斷服務(wù)其他客戶端。原理如下圖所示。
有一個(gè)更簡單的執(zhí)行其他程序的函數(shù)system,參數(shù)string傳遞給一個(gè)命令解釋器(一般為sh)執(zhí)行,即string被解釋為一條命令,由sh執(zhí)行該命令。若參數(shù)string為一個(gè)空指針,則檢查命令解釋器是否存在。該命令可以和同命令行下的命令形式相同,但由于命令作為一個(gè)參數(shù)放在系統(tǒng)調(diào)用中,應(yīng)注意編譯時(shí)對(duì)特殊意義字符的處理。命令的查找是按PATH環(huán)境變量的定義執(zhí)行的。命令所生成的后果一般不會(huì)對(duì)父進(jìn)程編程造成影響。返回值:當(dāng)參數(shù)為空指針時(shí),只有當(dāng)命令解釋器有效時(shí)返回值為非零。若參數(shù)不為空指針,返回值為該命令的返回狀態(tài)(同waitpid())的返回值。命令無效或語法錯(cuò)誤則返回非零值,所執(zhí)行的命令被終止。其他情況則返回-1.它是一個(gè)較高層的函數(shù),實(shí)際上相當(dāng)于在shell下執(zhí)行一條命令,除了system之外,系統(tǒng)調(diào)用exec來執(zhí)行一個(gè)可執(zhí)行文件,來代替當(dāng)前進(jìn)程的執(zhí)行映像。系統(tǒng)調(diào)用exit的功能是終止發(fā)出調(diào)用的進(jìn)程。sleep函數(shù)調(diào)用用來指定進(jìn)程掛起的秒數(shù)。wait函數(shù)族用來等待和控制進(jìn)程。poppen函數(shù)和system函數(shù)類似,區(qū)別是它用管道方式處理輸出。
父進(jìn)程和子進(jìn)程的關(guān)系是管理和被管理的關(guān)系,當(dāng)父進(jìn)程終止時(shí),子進(jìn)程也隨之而終止。但子進(jìn)程終止時(shí),父進(jìn)程并不一定終止。比如httpd服務(wù)器運(yùn)行時(shí),我們可以殺掉其子進(jìn)程,父進(jìn)程并不會(huì)因?yàn)樽舆M(jìn)程的終止而終止。
六.進(jìn)程的管理
1.啟動(dòng)進(jìn)程
輸入需要運(yùn)行的程序的程序名,執(zhí)行一個(gè)程序,其實(shí)也就是啟動(dòng)了一個(gè)進(jìn)程。在Linux系統(tǒng)中,每個(gè)進(jìn)程都具有一個(gè)進(jìn)程號(hào)(PID),用于系統(tǒng)識(shí)別和調(diào)度進(jìn)程。啟動(dòng)一個(gè)進(jìn)程有兩個(gè)主要途徑:手工啟動(dòng)和調(diào)度啟動(dòng),后者是事先進(jìn)行設(shè)置,根據(jù)用戶要求自動(dòng)啟動(dòng)。由用戶輸入命令,直接啟動(dòng)一個(gè)進(jìn)程便是手工啟動(dòng)進(jìn)程。但手工啟動(dòng)進(jìn)程又可以分為很多種,根據(jù)啟動(dòng)的進(jìn)程類型不同;性質(zhì)不同,實(shí)際結(jié)果也不一樣。
(1)前臺(tái)啟動(dòng)
前臺(tái)啟動(dòng)是手工啟動(dòng)一個(gè)進(jìn)程的最常用的方式。用戶鍵入一個(gè)命令“df”,就已經(jīng)啟動(dòng)了一個(gè)進(jìn)程,而且是一個(gè)前臺(tái)的進(jìn)程。這時(shí)候系統(tǒng)其實(shí)已經(jīng)處于多進(jìn)程狀態(tài)。有許多運(yùn)行在后臺(tái)的、系統(tǒng)啟動(dòng)時(shí)就已經(jīng)自動(dòng)啟動(dòng)的進(jìn)程正在悄悄運(yùn)行著。有的用戶在鍵入“df”命令以后趕緊使用“ps -x”查看,卻沒有看到df進(jìn)程,會(huì)覺得很奇怪。其實(shí)這里因?yàn)閐f這個(gè)進(jìn)程結(jié)束太快,使用ps查看時(shí)該進(jìn)程已經(jīng)執(zhí)行結(jié)束了。如果啟動(dòng)一個(gè)比較耗時(shí)的進(jìn)程,例如在根命令下運(yùn)行:find,然后使用ps aux查看,就會(huì)看到在里面有一個(gè)find進(jìn)程。
(2)后臺(tái)啟動(dòng)
直接從后臺(tái)手工啟動(dòng)一個(gè)進(jìn)程用得比較小一些,除非是該進(jìn)程甚為耗時(shí),且用戶也不急著需要結(jié)果。假設(shè)用戶要啟動(dòng)一個(gè)需要長時(shí)間運(yùn)行的格式化文本文件的進(jìn)程,為了不使整個(gè)shell在格式化過程中都處于“癱瘓”狀態(tài),從后臺(tái)啟動(dòng)這個(gè)進(jìn)程是明智的選擇。
2.進(jìn)程調(diào)度
當(dāng)需要中斷一個(gè)前臺(tái)進(jìn)程的時(shí)候,通常使用Ctrl+C組合鍵。但是對(duì)于一個(gè)后臺(tái)進(jìn)程,就不是一個(gè)組合鍵所能解決的了,這時(shí)就必須使用kill命令。該命令可以終止后臺(tái)進(jìn)程。至于終止后臺(tái)進(jìn)程的原因有很多,或許是該進(jìn)程占用的CPU時(shí)間過多;或許是該進(jìn)程已經(jīng)掛死。這種情況是經(jīng)常發(fā)生的。kill命令的工作原理是:向Linux系統(tǒng)的內(nèi)核發(fā)送一個(gè)系統(tǒng)操作信號(hào)和某個(gè)程序的進(jìn)程標(biāo)識(shí)號(hào),然后系統(tǒng)內(nèi)核就可以對(duì)進(jìn)程標(biāo)識(shí)號(hào)指定的進(jìn)程進(jìn)行操作。
七.Linux的第一個(gè)進(jìn)程:init
init是Linux系統(tǒng)執(zhí)行的第一個(gè)進(jìn)程,進(jìn)程ID為1,是系統(tǒng)所有進(jìn)程的起點(diǎn),主要用來執(zhí)行一些開機(jī)初始化腳本和監(jiān)視進(jìn)程。Linux系統(tǒng)在完成核內(nèi)引導(dǎo)以后就開始運(yùn)行init程序,init程序需要讀取配置文件/etc/inittab。Inittab是一個(gè)不可執(zhí)行的文本文件,它由若干行命令所組成。
在RHEL 4系統(tǒng)中,inittab配置文件的內(nèi)容如下所示:
Inittab配置文件每行的基本格式如下。
id:runlevels:action:procees
其中某些部分可以為空,下面我們逐一介紹。
1.id
1~2個(gè)字符,配置行的惟一標(biāo)識(shí),在配置文件中不能重復(fù)。
2.runlevels
配置行適用的運(yùn)行級(jí)別,在這里可填入多個(gè)運(yùn)行級(jí)別,比如12345或者35等。
Linux有7個(gè)運(yùn)行級(jí)別:
0:關(guān)機(jī)
1:單用戶字符界面
2:不具備網(wǎng)絡(luò)文件系統(tǒng)(NFS)功能的多用戶字符界面
3:具有網(wǎng)絡(luò)功能的多用戶字符界面
4:保留不用
5:具有網(wǎng)絡(luò)功能的圖形用戶界面
6:重新啟動(dòng)系統(tǒng)
3.a(chǎn)ction
init有如下幾種行為,如下表所示。
init行為
行為 |
描述 |
respawn |
啟動(dòng)并監(jiān)視第4項(xiàng)指定的process,若process終止則重啟它 |
wait |
執(zhí)行第4項(xiàng)指定的process,并等待它執(zhí)行完備 |
once |
執(zhí)行第4項(xiàng)指定的process |
boot |
不論在哪個(gè)執(zhí)行等級(jí),系統(tǒng)啟動(dòng)時(shí)都會(huì)運(yùn)行第4項(xiàng)指定的process |
bootwait |
不論在哪個(gè)執(zhí)行等級(jí),系統(tǒng)啟動(dòng)時(shí)都會(huì)運(yùn)行第4項(xiàng)指定的process,且一直等它執(zhí)行完備 |
off |
關(guān)閉任何動(dòng)作,相當(dāng)于忽略該配置行 |
ondemand |
進(jìn)入ondemand執(zhí)行等級(jí)時(shí),執(zhí)行第4項(xiàng)指定的process |
initdefault |
系統(tǒng)啟動(dòng)后進(jìn)入的執(zhí)行等級(jí),該行不需要指定process |
sysinit |
不論在哪個(gè)執(zhí)行等級(jí),系統(tǒng)會(huì)在執(zhí)行boot及bootwait之前執(zhí)行第4項(xiàng)指定的process |
powerwait |
當(dāng)系統(tǒng)的供電不足時(shí)執(zhí)行第4項(xiàng)指定的process,且一直等它執(zhí)行完備 |
powerfailnow |
當(dāng)系統(tǒng)的供電嚴(yán)重不足時(shí)執(zhí)行第4項(xiàng)指定的process |
ctrlaltdel |
當(dāng)用戶按下ctrl+alt+del 時(shí)執(zhí)行的操作 |
kbrequest |
當(dāng)用戶按下特殊的組合鍵時(shí)執(zhí)行第4項(xiàng)指定的process,此組合鍵需在keymaps文件定義 |
4.process
Process為init執(zhí)行的進(jìn)程,這些進(jìn)程都保存在目錄/etc/rc.d/rcX中,其中的X代表運(yùn)行級(jí)別,rc程序接收X參數(shù),然后運(yùn)行/etc/rc.d/rc.X下面的程序。使用如下命令可以查看/etc/rc.d目錄內(nèi)容。
使用如下命令查看/etc/rc.d/rc5.d的內(nèi)容。
這些文件都是符號(hào)鏈接,以S打頭的標(biāo)識(shí)啟動(dòng)該程序,而以K打頭的標(biāo)識(shí)終止該程序,后面的數(shù)字標(biāo)識(shí)執(zhí)行順序,越小越先執(zhí)行,剩下的標(biāo)識(shí)程序名。系統(tǒng)啟動(dòng)或者切換到該運(yùn)行級(jí)別時(shí)會(huì)執(zhí)行以S打頭的程序,系統(tǒng)切換到該運(yùn)行級(jí)別時(shí)會(huì)執(zhí)行以K打頭的程序。
這個(gè)目錄下的程序可通過chkconfig程序進(jìn)行管理,當(dāng)然這個(gè)目錄下的程序需要符合一定規(guī)范,如果了解shell編程,可以查看這些符號(hào)鏈接所指向的程序的源碼。
init也是一個(gè)進(jìn)程,和普通的進(jìn)程具有一樣的屬性。比如修改了/etc/inittab,想讓修改馬上生效,可通過運(yùn)行“kill-SIGHUP 1”來實(shí)現(xiàn),也可通過運(yùn)行“init q”來實(shí)現(xiàn)。
八.Linux的線程簡介
1.Linux線程的定義
線程(thread)是在共享內(nèi)存空間中并發(fā)的多道執(zhí)行路徑,它們共享一個(gè)進(jìn)程的資源,如文件描述和信號(hào)處理。在兩個(gè)普通進(jìn)程(非線程)間進(jìn)行切換時(shí),內(nèi)核準(zhǔn)備從一個(gè)進(jìn)程的上下文切換到另一個(gè)進(jìn)程的上下文要花費(fèi)很大的開銷。這里上下文切換的主要任務(wù)是保存老進(jìn)程CPU狀態(tài)并加載新進(jìn)程的保存狀態(tài),用新進(jìn)程的內(nèi)存映像替換進(jìn)程的內(nèi)存映像。線程允許你的進(jìn)程在幾個(gè)正在運(yùn)行的任務(wù)之間進(jìn)行切換,而不必執(zhí)行前面提到的完整的上下文。另外本文介紹的線程是針對(duì)POSIX線程的,也就是Pthread。也因?yàn)長inux對(duì)它的支持最好,相對(duì)進(jìn)程而言,線程是一個(gè)更加接近于執(zhí)行體的概念,它可以與同進(jìn)程中的其他線程共享數(shù)據(jù),但擁有自己的棧空間,擁有獨(dú)立的執(zhí)行序列。在串行程序基礎(chǔ)上引入線程和進(jìn)程是為了提高程序的并發(fā)度,從而提高程序運(yùn)行效率和響應(yīng)時(shí)間。也可以將線程和輕量級(jí)進(jìn)程(LWP)視為等同的,但其實(shí)在不同的系統(tǒng)/實(shí)現(xiàn)中有不同的解釋,LWP更恰當(dāng)?shù)慕忉尀橐粋€(gè)虛擬CPU或內(nèi)核的線程。它可以幫助用戶態(tài)線程實(shí)現(xiàn)一些特殊的功能。Pthread是一種標(biāo)準(zhǔn)化模型,它用來把一個(gè)程序分成一組能夠同時(shí)執(zhí)行的任務(wù)。
2.什么場合使用Pthread,即線程
(1)在返回前阻塞的I/O任務(wù)能夠使用一個(gè)線程處理I/O,同時(shí)繼續(xù)執(zhí)行其他處理任務(wù)。
(2)在有一個(gè)或多個(gè)任務(wù)受不確定性事件,比如網(wǎng)絡(luò)通信的可獲得性影響的場合,能夠使用線程處理這些異步事件,同時(shí)繼續(xù)執(zhí)行正常的處理。
(3)如果某些程序功能比其他的功能更重要,可以使用線程以保證所有功能都出現(xiàn),但那些時(shí)間密集型的功能具有更高的優(yōu)先級(jí)。
以上三點(diǎn)可以歸納為:在檢查程序中潛在的并行性時(shí),也就是說在要找出能夠同時(shí)執(zhí)行任務(wù)時(shí)使用Pthread。上面已經(jīng)介紹了,Linux進(jìn)程模型提供了執(zhí)行多個(gè)進(jìn)程的能力,已經(jīng)可以進(jìn)行并行或并發(fā)編程,可是純種能夠讓你對(duì)多個(gè)任務(wù)的控制程序更好、使用資源更少,因?yàn)橐粋€(gè)單一的資源,如全局變量,可以由多個(gè)線程共享。而且,在擁有多個(gè)處理器的系統(tǒng)上,多線程應(yīng)用會(huì)比用多個(gè)進(jìn)程實(shí)現(xiàn)的應(yīng)用執(zhí)行速度更快。
3.Linux進(jìn)程和線程的發(fā)展
1999年1月發(fā)布的Linux 2.2內(nèi)核中,進(jìn)程是通過系統(tǒng)調(diào)用fork創(chuàng)建的,新的進(jìn)程是原來進(jìn)程的子進(jìn)程。需要說明的是,在2.2.x版本中,不存在真正意義上的線程(thread)。Linux中常用的線程Pthread實(shí)際上是通過進(jìn)程來模擬的。也就是說Linux中的線程也是通過fork創(chuàng)建的,是“輕”進(jìn)程。Linux 2.2只默認(rèn)允許4096個(gè)進(jìn)程/線程同時(shí)運(yùn)行。高端系統(tǒng)同時(shí)要服務(wù)上千個(gè)用戶,所以這顯然是一個(gè)問題,它一度是阻礙Linux進(jìn)入企業(yè)級(jí)市場的一大因素。
2001年1月發(fā)布的Linux 2.4內(nèi)核消除了這個(gè)限制,并且允許在系統(tǒng)運(yùn)行中動(dòng)態(tài)調(diào)整進(jìn)程數(shù)上限。因此,進(jìn)程數(shù)現(xiàn)在只受制于物理內(nèi)存的多少。在高端服務(wù)器上,即使安裝了512MB內(nèi)存,現(xiàn)在也能輕而易舉地同時(shí)支持1萬6千個(gè)進(jìn)程。
2003年12月發(fā)布的2.6內(nèi)核,進(jìn)程調(diào)度經(jīng)過重新編寫,去掉了以前版本中效率不高的算法。以前,為了決定下一步要運(yùn)行哪一個(gè)任務(wù),進(jìn)程調(diào)度程序要查看每一個(gè)準(zhǔn)備好的任務(wù),并且經(jīng)過計(jì)算機(jī)來決定哪一個(gè)任務(wù)相對(duì)來更為重要。進(jìn)程標(biāo)識(shí)號(hào)(PID)的數(shù)目也從32000升到10億。內(nèi)核內(nèi)部的大改變之一就是Linux的線程框架被重寫,以使NPTL(Native POSIX Thread Library)可以運(yùn)行于其上。對(duì)于運(yùn)行負(fù)荷繁重的線程應(yīng)用的Pentium Pro及更先進(jìn)的處理器而言,這是一個(gè)主要的性能提升,也是企業(yè)級(jí)應(yīng)用中的很多高端系統(tǒng)一直以來所期待的。線程框架的改變包含Linux線程空間中的許多新的概念,包括線程組、線程各自的本地存儲(chǔ)區(qū)、POSIX風(fēng)格信號(hào),以及其他改變。改進(jìn)后的多線程和內(nèi)存管理技術(shù)有助于更好地運(yùn)行大型多媒體應(yīng)用軟件。
4.總結(jié)
線程和進(jìn)程在使用上各有優(yōu)缺點(diǎn):線程執(zhí)行開銷小,但不利于資源的管理和保護(hù);而進(jìn)程正相反。同時(shí),線程適合于在對(duì)稱處理器的計(jì)算機(jī)上運(yùn)行,而進(jìn)程則可以跨機(jī)器遷移。另外,進(jìn)程可以擁有資源,線程共享進(jìn)程擁有的資源。進(jìn)程間的切換必須保存在進(jìn)程控制塊PCB(Process Control Block)中。同一個(gè)進(jìn)程的多個(gè)線程間的切換不用那么麻煩。最后一個(gè)實(shí)例來作為本文的結(jié)束:當(dāng)你在一臺(tái)Linux PC上打開兩個(gè)OICQ,每一個(gè)OICQ是一個(gè)進(jìn)程;而當(dāng)你在一個(gè)OICQ上和多人聊天時(shí),每一個(gè)聊天窗口就是一個(gè)線程。
標(biāo)簽:茂名 衡陽 慶陽 三門峽 湘西 仙桃 衡陽 六盤水
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Linux進(jìn)程和線程的基礎(chǔ)與管理》,本文關(guān)鍵詞 Linux,進(jìn)程,和,線程,的,基礎(chǔ),;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。