最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

終于有人把進程與線程講清楚了

2020-09-22 17:26 作者:博毅創(chuàng)為  | 我要投稿

前言

很多人對進程、線程沒有什么概念,面試的時候也說不出其中的核心內(nèi)涵。

所以,今天我打算花點篇幅把進程線程講清楚。

01 CPU與內(nèi)存

**CPU **大家都知道是計算機的中央運算單元,用來計算的。

CPU從內(nèi)存里面讀取一條一條的代碼指令,然后根據(jù)指令來執(zhí)行運算(加,減,乘,除,復(fù)制數(shù)據(jù)等)。

CPU在運算的過程中一些數(shù)據(jù)存放在CPU的寄存器和內(nèi)存里面。

CPU里面有各種寄存器,各司其職。指令指針寄存器存放的是當(dāng)前執(zhí)行到那條代碼指令了。代碼指令是寫完程序后被編譯器編譯成二進制指令代碼


02 內(nèi)核與虛擬內(nèi)存

電腦或手機開機以后,上電跑啟動代碼,運行OS內(nèi)核,內(nèi)核里也有線程,這個我們把它叫做內(nèi)核態(tài)

內(nèi)核啟動以后, 內(nèi)核將物理內(nèi)存管理起來。內(nèi)核提供虛擬內(nèi)存管理機制給每個進程(應(yīng)用程序App)內(nèi)存服務(wù)。

它的思路是什么呢?每個進程(應(yīng)用App) 都有自己的虛擬內(nèi)存空間,注意這里的空間只是一個數(shù)字空間,沒有劃分實際的物理內(nèi)存。

這樣做的好處是多個進程(應(yīng)用App)內(nèi)存都是獨立的相互不影響,物理內(nèi)存只有一個,多個進程(應(yīng)用App)不會因為直接使用物理內(nèi)存而沖突。


那么OS是如何管理物理內(nèi)存的呢?進程(應(yīng)用App)需要內(nèi)存的時候,OS分配一塊虛擬內(nèi)存(起點---終點),然后OS在從自己管理的物理內(nèi)存里面分配出來物理內(nèi)存頁,然后通過一個MMU的單元,將分配的虛擬內(nèi)存與物理內(nèi)存頁映射起來,這樣,讀寫虛擬內(nèi)存地址最終通過映射來使用物理內(nèi)存地址,這樣每個進程之間的內(nèi)存是獨立的,安全的。每個進程會把虛擬內(nèi)存空間分成4個段(代碼段, 數(shù)據(jù)端,堆,棧)

代碼段:用來存放進程(應(yīng)用App)的代碼指令。

數(shù)據(jù)端:用來存放全局變量的內(nèi)存。

:調(diào)用os的malloc/free 來動態(tài)分配的內(nèi)存。

:用來存放局部變量,函數(shù)參數(shù),函數(shù)調(diào)用與跳轉(zhuǎn)。

每個進程(應(yīng)用App)相當(dāng)于一個容器,所有應(yīng)用App里面需要的資源和機制都在進程里面。

線程是OS獨立調(diào)度執(zhí)行的單元,OS調(diào)度執(zhí)行的單位就是線程,線程需要以進程作為容器和使用進程相關(guān)的環(huán)境。

應(yīng)用態(tài)沒有進程就不會有線程。

03 進程與線程

上面說過進程是容器,應(yīng)用態(tài)的線程必須要基于進程來創(chuàng)建出來。

那么進程與線程他們之間到底是一個什么樣的關(guān)系,接下來我們來分析一下。


例如"在桌面上雙擊打開一個App", 桌面App程序會調(diào)用OS的系統(tǒng)調(diào)用接口fork,讓OS 創(chuàng)建一個進程出來,OS為你準(zhǔn)備好進程的結(jié)構(gòu)體對象,將這個App的文件(xxx.exe, 存放編譯好的代碼指令)加載到進程的代碼段,同時OS會為你創(chuàng)建一個線程(main thread), 在代碼里面,還可以調(diào)用OS的接口,來創(chuàng)建多個線程,這樣OS就可以調(diào)度這些線程執(zhí)行了。

虛擬內(nèi)存空間是進程的概念,那么線程如何使用的呢?各線程使用共享進程的代碼段,數(shù)據(jù)段,堆,每個線程在進程的??臻g創(chuàng)建一個屬于自己的棧空間。

所以這樣就得到一些結(jié)論如下:

每個線程共享進程的代碼段內(nèi)存空間,所以我們編寫多線程代碼的時候,可以在任何線程調(diào)用任何函數(shù)。

每個線程共享進程的數(shù)據(jù)段內(nèi)存空間,所以我們編寫多線程代碼的時候,可以在任何線程訪問全局變量。

每個線程共享進程的堆,所以我們編寫多線程代碼的時候,可以在一個線程訪問另外一個線程new/malloc出來的內(nèi)存對象。

每個線程都有自己的棧的空間,所以可以獨立調(diào)用執(zhí)行函數(shù)(參數(shù),局部變量,函數(shù)跳轉(zhuǎn))相互之間不受影響。


04 OS如何調(diào)度線程的

CPU一般會有多個核心,每個核心都調(diào)度一個線程執(zhí)行。

CPU有幾個核心,最多同時可調(diào)度幾個線程(多核能讓電腦更快就是這個原理)。

OS的功能就是要在合適的時候分配CPU核心來調(diào)度合適的線程。

為了能實現(xiàn)多任務(wù)并發(fā),OS不允許一個OS核心長期固定調(diào)度一個線程。

OS是如何調(diào)度CPU核心來執(zhí)行各個線程呢?


OS會根據(jù)線程的優(yōu)先級分配每次調(diào)度最多執(zhí)行的時間片,這個時間一到,無論如何都要重新調(diào)度一次線程(也許還是調(diào)度到這個線程,這個不重要)。

除了時間片以外,線程會等待某些條件(磁盤讀取文件,網(wǎng)卡發(fā)送完數(shù)據(jù),線程休眠, 等待用戶操作)這樣也會把這個線程掛起,OS會重新找一個新的線程繼續(xù)執(zhí)行,只到掛起的這個線程的條件滿足了,重新把這個線程放到可調(diào)度隊列里面,這個線程又有機會被OS調(diào)度CPU核心來執(zhí)行。

當(dāng)我們打開電腦的任務(wù)管理器,你會發(fā)現(xiàn)很多線程的CPU占有率為0%, 說明這些線程都由于某些條件而掛起了,沒有被OS調(diào)度。

每個線程“隨時隨地”都可能被OS中斷執(zhí)行,并調(diào)度到其它的線程執(zhí)行。

OS是如何保證一個線程在調(diào)度出去后,再重新調(diào)度回來能繼續(xù)之前的數(shù)據(jù)狀態(tài)來執(zhí)行呢?


OS是這么做的:每個線程都會有一個運行時的環(huán)境(運行時CPU的每個寄存器的值、棧獨立。棧的內(nèi)存數(shù)據(jù)不會變。數(shù)據(jù)段、堆共用,可能調(diào)度回來會變)。

當(dāng)OS要把某個CPU核心調(diào)度出去給其它線程的時候,首先會把當(dāng)前線程的運行環(huán)境(寄存器的值等)保存到內(nèi)存,然后調(diào)度到其它線程,等再次調(diào)度回來的時候,再把原來保存到內(nèi)存的寄存器的值,再設(shè)置會CPU核心的寄存器里面,這樣就回到了調(diào)度出去之前的進度。

因為多線程之間共用了代碼段(代碼段只讀,不會改),數(shù)據(jù)段(全局變量調(diào)度回來后,可能被其它線程篡改,不是調(diào)度之前的那個值了),堆(調(diào)度回來后,動態(tài)內(nèi)存分配的對象內(nèi)存數(shù)據(jù)可能被其它線程出篡改),調(diào)度回來后,棧上的數(shù)據(jù)是不變的,因為每個線程都有自己的棧空間。線程調(diào)度前后哪些會變,哪些不變你要清楚。這樣你寫多線程代碼的時候才能清晰。

線程調(diào)度的開銷就是:保存上下文執(zhí)行環(huán)境,內(nèi)核態(tài)運行算法決定接下來調(diào)度那個線程,切換這個線程的上下文環(huán)境。

05 線程鎖的核心原理是什么?

多線程切換的時候,棧、代碼段的數(shù)據(jù)不會變,數(shù)據(jù)段與堆的數(shù)據(jù)切換前后可能會發(fā)生改變,這個就造成了"競爭", 如果某些關(guān)鍵數(shù)據(jù),在執(zhí)行代碼的時候,不允許這種競爭性的改變,怎么辦呢?這個時候多線程就給了一個機制,這個機制就是鎖,那么鎖的原理是什么?接下來我來這你詳細講解。


例如: 我編寫一個函數(shù)

funcA() { ? ?lock(鎖) ? // 要保護的數(shù)據(jù)的邏輯部分。 ? ?… ? ?unlock(鎖) }

當(dāng)線程A調(diào)用FuncA(),線程B也調(diào)用FUNCA(),OS如何設(shè)計鎖能保證他們競爭的唯一性的呢?我們把具體過程來分析一下。

假設(shè)線程A調(diào)用funcA();它獲取了鎖,執(zhí)行到中間某個代碼的時候,時間片用完了,被OS調(diào)度出去,OS調(diào)度線程B來執(zhí)行funcA(), 當(dāng)線程B跑到lock(鎖),發(fā)現(xiàn)這個鎖已經(jīng)被線程A拿了,此時,線程B會主動把自己掛起到鎖這個“事件”上(等著鎖釋放)。

OS從新調(diào)度線程執(zhí)行,當(dāng)重新調(diào)度到線程A的時候,線程A執(zhí)行,執(zhí)行完成以后,釋放掉這個鎖,那么線程B又從等待這個鎖的隊列,到線程調(diào)度的就緒隊列,又可被OS調(diào)度到,等線程A調(diào)度出去后,線程B去lock這個鎖,就占用了這個鎖,然后繼續(xù)執(zhí)行。這樣就保證了lock/unlock之間的代碼永遠只有一個線程跑進去了。這樣保護了這段代碼里面相關(guān)的數(shù)據(jù)和邏輯。


進程與線程各位老鐵一定要掌握好,這樣寫程序才能做到心中用代碼。

好了,今天的分享就到這里,謝謝大家收看,我們下期再見。

END


終于有人把進程與線程講清楚了的評論 (共 條)

分享到微博請遵守國家法律
阳江市| 穆棱市| 泸溪县| 中阳县| 长武县| 封开县| 拉萨市| 苏州市| 宁国市| 琼海市| 元谋县| 崇州市| 理塘县| 横山县| 宝鸡市| 定日县| 浮山县| 岳阳市| 平舆县| 南安市| 福安市| 大田县| 嫩江县| 景宁| 苗栗县| 广河县| 义马市| 永定县| 千阳县| 五寨县| 萝北县| 阿图什市| 昭通市| 嘉鱼县| 方山县| 宁德市| 乐昌市| 五台县| 固阳县| 邯郸县| 且末县|