進(jìn)程猎贴,在一定的環(huán)境下杆融,把靜態(tài)的程序代碼運(yùn)行起來拙徽,通過使用不同的資源缔赠,來完成一定的任務(wù)年堆。比如說产艾,進(jìn)程的環(huán)境包括環(huán)境變量旷坦,進(jìn)程所掌控的資源白热,有中央處理器庸诱,有內(nèi)存捻浦,打開的文件,映射的網(wǎng)絡(luò)端口等等桥爽。
線程作為進(jìn)程的一部分朱灿,扮演的角色就是怎么利用中央處理器去運(yùn)行代碼。這其中牽扯到的最重要資源的是中央處理器和其中的寄存器钠四,和線程的棧(stack)盗扒。這里想強(qiáng)調(diào)的是,線程關(guān)注的是中央處理器的運(yùn)行缀去,而不是內(nèi)存等資源的管理侣灶。
相同點(diǎn):
無論是進(jìn)程還是線程,對于程序員而言缕碎,都是用來實(shí)現(xiàn)多任務(wù)并發(fā)的技術(shù)手段褥影。二者都可以獨(dú)立調(diào)度,因此在多任務(wù)環(huán)境下咏雌,功能上并無差異凡怎。并且二者都具有各自的實(shí)體校焦,是系統(tǒng)獨(dú)立管理的對象個體。所以在系統(tǒng)層面栅贴,都可以通過技術(shù)手段實(shí)現(xiàn)二者的控制斟湃。而且二者所具有的狀態(tài)都非常相似。而且檐薯,在多任務(wù)程序中凝赛,子進(jìn)程(子線程)的調(diào)度一般與父進(jìn)程(父線程)平等競爭。
其實(shí)在Linux內(nèi)核2.4版以前坛缕,線程的實(shí)現(xiàn)和管理方式就是完全按照進(jìn)程方式實(shí)現(xiàn)的墓猎。在2.6版內(nèi)核以后才有了單獨(dú)的線程實(shí)現(xiàn)。
不同點(diǎn):
“進(jìn)程是資源分配的基本單位赚楚,線程是調(diào)度的基本單位毙沾。”這是教材上的經(jīng)典描述宠页,這也確實(shí)是二者的顯著區(qū)別左胞,線程是最小的調(diào)度單位,進(jìn)程當(dāng)然也可以被調(diào)度举户,分配資源時的對象必須是進(jìn)程烤宙,所以要想運(yùn)行一個任務(wù),需要獲取資源俭嘁,至少要有進(jìn)程躺枕。
簡而言之,進(jìn)程的個體間是完全獨(dú)立的供填,而線程間是彼此依存的拐云。多進(jìn)程環(huán)境中,任何一個進(jìn)程的終止近她,不會影響到其他進(jìn)程叉瘩。而多線程環(huán)境中,父線程終止粘捎,全部子線程被迫終止(沒有了資源)薇缅。而任何一個子線程終止一般不會影響其他線程,除非子線程執(zhí)行了exit()系統(tǒng)調(diào)用晌端。任何一個子線程執(zhí)行exit()捅暴,全部線程同時滅亡恬砂。
從實(shí)現(xiàn)的角度來看:
開發(fā)者大多從實(shí)際使用中來對比二者的區(qū)別咧纠,進(jìn)程是實(shí)現(xiàn)fork系統(tǒng)的調(diào)用,pid_t fork(void);
而線程則是實(shí)現(xiàn)clone系統(tǒng)的調(diào)用泻骤,int clone(int (*fn)(void *),void *child_stack,int flags,void *arg, ...);
其中漆羔,frok()是將所有資源復(fù)制給了子進(jìn)程梧奢,而clone則是一小部分必要的資源,clone函數(shù)可以通過參數(shù)控制要復(fù)制的對象演痒。
實(shí)際中亲轨,編寫多進(jìn)程程序時采用fork創(chuàng)建子進(jìn)程實(shí)體。而創(chuàng)建線程時并不采用clone系統(tǒng)調(diào)用鸟顺,而是采用線程庫函數(shù)惦蚊,因此在多線程程序中看到的是pthread_create而非clone。
vfork()也是一個系統(tǒng)調(diào)用讯嫂,用來創(chuàng)建一個新的進(jìn)程蹦锋。它創(chuàng)建的進(jìn)程并不復(fù)制父進(jìn)程的資源空間,而是共享欧芽,也就說實(shí)際上vfork實(shí)現(xiàn)的是一個接近線程的實(shí)體莉掂,只是以進(jìn)程方式來管理它。并且千扔,vfork()的子進(jìn)程與父進(jìn)程的運(yùn)行時間是確定的:子進(jìn)程“結(jié)束”后父進(jìn)程才運(yùn)行憎妙。請讀者注意“結(jié)束”二字。并非子進(jìn)程完成退出之意曲楚,而是子進(jìn)程返回時厘唾。一般采用vfork()的子進(jìn)程,都會緊接著執(zhí)行execv啟動一個全新的進(jìn)程洞渤,該進(jìn)程的進(jìn)程空間與父進(jìn)程完全獨(dú)立不相干阅嘶,所以不需要復(fù)制父進(jìn)程資源空間。此時载迄,execv返回時父進(jìn)程就認(rèn)為子進(jìn)程“結(jié)束”了讯柔,自己開始運(yùn)行。實(shí)際上子進(jìn)程繼續(xù)在一個完全獨(dú)立的空間運(yùn)行著护昧。
實(shí)體間(進(jìn)程間魂迄,線程間,進(jìn)線程間)通信方式的不同
進(jìn)程間的通信方式有這樣幾種:
A.共享內(nèi)存 B.消息隊(duì)列 C.信號量 D.有名管道 E.無名管道 F.信號 G.文件 H.socket
線程間的通信方式上述進(jìn)程間的方式都可沿用惋耙,且還有自己獨(dú)特的幾種:
A.互斥量 B.自旋鎖 C.條件變量 D.讀寫鎖 E.線程信號 G.全局變量
值得注意的是捣炬,線程間通信用的信號不能采用進(jìn)程間的信號,因?yàn)樾盘柺腔谶M(jìn)程為單位的绽榛,而線程是共屬于同一進(jìn)程空間的湿酸。故而要采用線程信號。
綜上灭美,進(jìn)程間通信手段有8種推溃。線程間通信手段有13種。
控制方式的不同
進(jìn)程與線程的身份標(biāo)示ID管理方式不一樣届腐,進(jìn)程的ID為pid_t類型铁坎,實(shí)際為一個int型的變量蜂奸,在全系統(tǒng)中,進(jìn)程ID是唯一標(biāo)識硬萍,對于進(jìn)程的管理都是通過PID來實(shí)現(xiàn)的扩所。每創(chuàng)建一個進(jìn)程,內(nèi)核去中就會創(chuàng)建一個結(jié)構(gòu)體來存儲該進(jìn)程的全部信息朴乖;
每一個存儲進(jìn)程信息的節(jié)點(diǎn)也都保存著自己的PID祖屏。需要管理該進(jìn)程時就通過這個ID來實(shí)現(xiàn)(比如發(fā)送信號)。當(dāng)子進(jìn)程結(jié)束要回收時(子進(jìn)程調(diào)用exit()退出或代碼執(zhí)行完)买羞,需要通過wait()系統(tǒng)調(diào)用來進(jìn)行赐劣,未回收的消亡進(jìn)程會成為僵尸進(jìn)程,其進(jìn)程實(shí)體已經(jīng)不復(fù)存在哩都,但會虛占PID資源魁兼,因此回收是有必要的。
線程的ID是一個long型變量漠嵌,它的范圍大得多咐汞,管理方式也不一樣。線程ID一般在本進(jìn)程空間內(nèi)作用就可以了儒鹿,當(dāng)然系統(tǒng)在管理線程時也需要記錄其信息化撕。其方式是,在內(nèi)核創(chuàng)建一個內(nèi)核態(tài)線程與之對應(yīng)约炎,也就是說每一個用戶創(chuàng)建的線程都有一個內(nèi)核態(tài)線程對應(yīng)植阴。但這種對應(yīng)關(guān)系不是一對一,而是多對一的關(guān)系圾浅,也就是一個內(nèi)核態(tài)線程可以對應(yīng)著多個用戶級線程掠手。
對于線程而言,若要主動終止需要調(diào)用pthread_exit() 狸捕,主線程需要調(diào)用pthread_join()來回收(前提是該線程沒有被detached喷鸽,相關(guān)概念請查閱線程的“分離屬性”)。像線發(fā)送線程信號也是通過線程ID實(shí)現(xiàn)的灸拍。