概念
1.進(jìn)程與線程
- 每個app或者軟件啟動后都會執(zhí)行加載程序并執(zhí)行,一個app執(zhí)行的過程就是一個進(jìn)程,操作系統(tǒng)會為進(jìn)程分配獨立的虛擬內(nèi)存空間與資源。每個進(jìn)程之間資源不共享。為了解決資源共享的問題,例如視頻播放器邊下載邊解碼邊播放,在進(jìn)程中又細(xì)分線程。進(jìn)程是資源分配的基本單位,線程是cpu執(zhí)行的基本單位。一個進(jìn)程內(nèi)的線程共享進(jìn)程內(nèi)的資源。但又獨立搶占cpu時間片。
note:為什么不用多進(jìn)程,而用多線程,一是因為進(jìn)程上下文切換花銷大,同一個進(jìn)程內(nèi)的線程上下文切換只需要更改自己獨立的寄存器以及棧部分,其余虛擬空間無需改變,二是因為多進(jìn)程通信不如多線程通信方便。- 為了同一時間能夠啟動多個app,cpu分割了時間片給執(zhí)行的線程。這種是并發(fā)執(zhí)行,并非并行執(zhí)行。多核cpu能夠并行執(zhí)行。
進(jìn)程的虛擬空間分為內(nèi)核空間和用戶空間,用戶空間各個進(jìn)程獨有,內(nèi)核空間都映射到同一個物理地址,這是進(jìn)程通信的一種方式。當(dāng)進(jìn)程執(zhí)行系統(tǒng)調(diào)用時,會陷入內(nèi)核態(tài),可以讀寫內(nèi)核空間。
2.進(jìn)程的狀態(tài)
- 就緒態(tài):進(jìn)程分配了資源能夠搶占cpu時間片的狀態(tài)
- 運行態(tài):進(jìn)程搶占到cpu時間片,cpu執(zhí)行的狀態(tài)
- 阻塞態(tài):進(jìn)程因為輸入輸出IO或者代碼約束(wait,sleep)原因,需要阻塞,讓出cpu的執(zhí)行權(quán),這時使用DMA或者通道執(zhí)行IO操作,IO完成后產(chǎn)生中斷事件,進(jìn)程進(jìn)入就緒態(tài),可以開始搶占cpu時間片
- 其他狀態(tài)
- 創(chuàng)建狀態(tài):進(jìn)程創(chuàng)建成功進(jìn)入的狀態(tài),這是還沒有分配資源,不能搶占cpu
- 結(jié)束狀態(tài):進(jìn)程執(zhí)行完成
- 掛起狀態(tài):因為計算機(jī)內(nèi)存資源緊張而被換出的進(jìn)程,分為就緒掛起和阻塞掛起
- 就緒掛起:當(dāng)新建一個進(jìn)程時,因為計算機(jī)沒有足夠的內(nèi)存分配給進(jìn)程,所以進(jìn)入了就緒掛起
阻塞掛起,當(dāng)進(jìn)程進(jìn)入阻塞時,計算機(jī)因缺少內(nèi)存會優(yōu)先換出阻塞的進(jìn)程供其他進(jìn)程使用,這些阻塞進(jìn)程就進(jìn)入了阻塞掛起狀態(tài)
note:需要進(jìn)程掛起時會優(yōu)先考慮優(yōu)先級,然后考慮阻塞進(jìn)程,就緒進(jìn)程(延遲創(chuàng)建)掛起進(jìn)程因為不在內(nèi)存中,所以不能執(zhí)行。
aa.PNG
note:阻塞/掛起->阻塞:這種轉(zhuǎn)化在設(shè)計中比較少見。如果一個進(jìn)程沒有準(zhǔn)備好執(zhí)行,并且不在內(nèi)存中,調(diào)入它又有什么意義?
阻塞掛起->就緒掛起:如果等待的事件發(fā)生了
3.進(jìn)程運行以及切換
- pcb(保存進(jìn)程標(biāo)識,狀態(tài),打開文件表,進(jìn)程切換時保存的寄存器信息等)進(jìn)程信息的結(jié)構(gòu)體,相同狀態(tài)的pcb以鏈表的形式連接,形成阻塞隊列,就緒隊列等。
- 進(jìn)程創(chuàng)建后,構(gòu)造pcb結(jié)構(gòu)體并連接在就緒隊列中等待調(diào)度
- 進(jìn)程阻塞,暫停運行,并將pcb連接到阻塞隊列中等待事件完成
- 進(jìn)程喚醒,等待事件完成pcb從阻塞隊列移除,并連接在就緒隊列等待調(diào)度
- 進(jìn)程上下文切換,將進(jìn)程寄存器信息保存到pcb中,等現(xiàn)場恢復(fù)時讀取pcb繼續(xù)執(zhí)行
note:cpu調(diào)度實際上是線程的調(diào)度,進(jìn)程只有一個線程則線程的調(diào)度相當(dāng)于進(jìn)程的調(diào)度。
4.線程
- 為什么要出現(xiàn)線程?當(dāng)編寫word文檔時,我可以一邊編輯文檔一邊保存,如果只有進(jìn)程,那么只能在編寫好文檔之后才能執(zhí)行保存動作。
- 線程是進(jìn)程中更細(xì)粒度的執(zhí)行單元,在進(jìn)程中創(chuàng)建,所以進(jìn)程中的各個線程擁有相同的用戶地址空間,只有堆棧信息,寄存器和程序計數(shù)器不同。
- 線程切換只需要將執(zhí)行線程的寄存器信息和程序計數(shù)器送往cpu,并還原堆棧信息即可完成新線程切換。
5.線程模型
- 用戶級線程:在用戶空間創(chuàng)建,銷毀和切換線程,不需要內(nèi)核的參與。在用戶空間內(nèi)創(chuàng)建,以進(jìn)程的名義申請cpu時間片,然后進(jìn)程根據(jù)自身的線程調(diào)度算法調(diào)度線程。內(nèi)核感知不到進(jìn)程內(nèi)的線程,線程控制表存放在用戶空間(線程創(chuàng)建銷毀和調(diào)度都屬于用戶空間,只有系統(tǒng)調(diào)用的時候才需要內(nèi)核態(tài)的參與)。
- 優(yōu)點:只需要在用戶空間上調(diào)度線程,不需要內(nèi)核態(tài)與用戶態(tài)的切換,可以自己制定調(diào)度算法。
- 缺點:不能進(jìn)行系統(tǒng)調(diào)用,需要通過中間平臺運行時系統(tǒng)調(diào)用系統(tǒng)。由于內(nèi)核感知不到線程,所以只能以進(jìn)程為單位分配時間片。一旦線程阻塞,則該進(jìn)程中的其他線程都不能執(zhí)行,不能充分利用多核。
- 內(nèi)核級線程:在內(nèi)核中創(chuàng)建,銷毀并管理的線程,所以需要轉(zhuǎn)換成內(nèi)核態(tài)執(zhí)行線程管理。
優(yōu)點:充分利用多核,能夠利用時鐘中斷進(jìn)行時間片輪詢。缺點:線程管理代價大,需要由用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài),內(nèi)核創(chuàng)建銷毀線程。再由內(nèi)核態(tài)轉(zhuǎn)為用戶態(tài),線程控制表存放在內(nèi)核空間,所以內(nèi)核線程數(shù)會受到限制。
用戶線程與內(nèi)核線程的區(qū)別- note:用戶級線程的線程控制(tcb:存放線程控制寄存器及堆棧信息的)表在用戶空間中,而內(nèi)核級線程的線程控制表在內(nèi)核態(tài)中,由內(nèi)核調(diào)度,所以內(nèi)核線程管理需要轉(zhuǎn)換到內(nèi)核態(tài)。
- lwp(輕量級進(jìn)程):輕量級線程(LWP)是一種由內(nèi)核支持的用戶線程。它是基于內(nèi)核線程的高級抽象,因此只有先支持內(nèi)核線程,才能有LWP。每一個進(jìn)程可以有一個或多個LWPs,每個LWP由一個內(nèi)核線程支持。它位于用戶層和系統(tǒng)層之間。系統(tǒng)對線程資源的分配、對線程的控制是通過輕進(jìn)程來實現(xiàn)的,一個輕進(jìn)程可以控制一個或多個線程。CPU時間片的調(diào)度是面向輕進(jìn)程的。
- 線程模型:用戶執(zhí)行系統(tǒng)調(diào)用時需要進(jìn)入內(nèi)核態(tài),當(dāng)我們使用不同的線程執(zhí)行系統(tǒng)調(diào)用時,會有不同的阻塞情況。
- 多對一模型:用戶線程使用系統(tǒng)調(diào)用可以是兩種方式,一是通過運行時系統(tǒng)執(zhí)行系統(tǒng)調(diào)用,二是通過lwp建立關(guān)聯(lián)。第一種情況這樣的影響是一個用戶線程io阻塞,則整個進(jìn)程都將阻塞(內(nèi)核感受不到線程存在,會阻塞進(jìn)程,因為內(nèi)核中沒有線程表,只有進(jìn)程表會阻塞整個進(jìn)程,讓其他進(jìn)程執(zhí)行)。第二種情況下lwp成為cpu時間片分配的單位,但是如果進(jìn)程內(nèi)的所有線程都關(guān)聯(lián)同一個lwp,則和第一種情況相同。
- 一對一模型:使用內(nèi)核線程,或者每個用戶線程都關(guān)聯(lián)不同的lwp,這樣任何一個線程阻塞,都不會影響其他線程的調(diào)度。
- 多對多模型:lwp作為用戶線程和內(nèi)核線程關(guān)聯(lián)的橋梁,一個進(jìn)程中可以有多個lwp,一個lwp可以有多個用戶線程,lwp有關(guān)聯(lián)一個內(nèi)核線程,這樣一個用戶線程的io阻塞,不會影響整個進(jìn)程。這種屬于用戶線程與內(nèi)核線程混合使用的方式
- note:java中的線程屬于內(nèi)核及線程,原因有兩點,第一進(jìn)程內(nèi)的單個線程阻塞不會影響其他線程的運行。第二基本沒有辦法控制線程的執(zhí)行順序以及執(zhí)行次數(shù)。我遵照下面的程序編寫了1000個線程同時睡眠一分鐘,然后任務(wù)管理器中的線程數(shù)就從三千多瞬間升到四千多,這也說明java線程屬于內(nèi)核及線程。所以java線程的上下文切換消耗很大。
public class ThreadTest {
public static void main(String[] args) {
for (int i = 0; i < 1000; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(120);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在執(zhí)行任務(wù)");
}
});
thread.start();
}
}
}
5.調(diào)度算法
- 非搶占式:線程執(zhí)行完成或者阻塞后讓出cpu使用權(quán)
- 搶占式:在某段時間結(jié)束后,線程如果沒有執(zhí)行完或者阻塞,發(fā)生時鐘中斷。掛起改成供其他線程使用。
其他
smp:對稱處理器,多核cpu中的每個cpu地位相同,都可以完整訪問內(nèi)存和io設(shè)備
參考:https://blog.csdn.net/freeelinux/article/details/53562592(掛起狀態(tài))
https://mp.weixin.qq.com/s/YXl6WZVzRKCfxzerJWyfrg(進(jìn)程知識點)
http://www.itdecent.cn/p/49e3e47d41f0 (線程模型)
https://www.cnblogs.com/feng9exe/p/6803257.html(線程種類及模型)
https://blog.csdn.net/lihaidong1991/article/details/88861123(線程模型)
https://www.cnblogs.com/feng9exe/p/7890934.html(線程)
https://www.zhihu.com/question/307787570(用戶級線程的作用)
