<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    看完了進(jìn)程同步與互斥機(jī)制,我終于徹底理解了 PV 操作

    共 3882字,需瀏覽 8分鐘

     ·

    2021-02-28 19:11

    全文脈絡(luò)思維導(dǎo)圖如下:

    1. 什么是進(jìn)程同步

    在多道批處理系統(tǒng)中,多個(gè)進(jìn)程是可以并發(fā)執(zhí)行的,但由于系統(tǒng)的資源有限,進(jìn)程的執(zhí)行不是一貫到底的, 而是走走停停,以不可預(yù)知的速度向前推進(jìn),這就是進(jìn)程的「異步性」

    那么,「進(jìn)程的異步性會(huì)帶來什么問題呢」?舉個(gè)例子,如果有 A、B 兩個(gè)進(jìn)程分別負(fù)責(zé)讀和寫數(shù)據(jù)的操作,這兩個(gè)線程是相互合作、相互依賴的。那么寫數(shù)據(jù)應(yīng)該發(fā)生在讀數(shù)據(jù)之前。而實(shí)際上,由于異步性的存在,可能會(huì)發(fā)生先讀后寫的情況,而此時(shí)由于緩沖區(qū)還沒有被寫入數(shù)據(jù),讀進(jìn)程 A 沒有數(shù)據(jù)可讀,因此讀進(jìn)程 A 被阻塞。

    進(jìn)程同步(synchronization)就是用來解決這個(gè)問題的。從上面的例子我們能看出,一個(gè)進(jìn)程的執(zhí)行可能影響到另一個(gè)進(jìn)程的執(zhí)行,「所謂進(jìn)程同步就是指協(xié)調(diào)這些完成某個(gè)共同任務(wù)的并發(fā)線程,在某些位置上指定線程的先后執(zhí)行次序、傳遞信號或消息」。

    再舉個(gè)生活中的進(jìn)程同步的例子,你想要喝熱水,于是你打了一壺水開始燒,在這壺水燒開之前,你只能一直等著,水燒開之后水壺自然會(huì)發(fā)生響聲提醒你來喝水,于是你就可以喝水了。就是說「水燒開這個(gè)事情必須發(fā)生在你喝水之前」。

    注意不要把進(jìn)程同步和進(jìn)程調(diào)度搞混了:

    • 進(jìn)程調(diào)度是為了最大程度的利用 CPU 資源,選用合適的算法調(diào)度就緒隊(duì)列中的進(jìn)程。
    • 進(jìn)程同步是為了協(xié)調(diào)一些進(jìn)程以完成某個(gè)任務(wù),比如讀和寫,你肯定先寫后讀,不能先讀后寫吧,這就是進(jìn)程同步做的事情了,指定這些進(jìn)程的先后執(zhí)行次序使得某個(gè)任務(wù)能夠順利完成。

    2. 什么是進(jìn)程互斥

    同樣的,也是因?yàn)檫M(jìn)程的并發(fā)性,并發(fā)執(zhí)行的線程不可避免地需要共享一些系統(tǒng)資源,比如內(nèi)存、打印機(jī)、攝像頭等。舉個(gè)例子:我們?nèi)W(xué)校打印店打印論文,你按下了 WPS 的 “打印” 選項(xiàng),于是打印機(jī)開始工作。你的論文打印到一半時(shí),另一位同學(xué)按下了 Word 的 “打印” 按鈕,開始打印他自己的論文。想象一下如果兩個(gè)進(jìn)程可以隨意的、并發(fā)的共享打印機(jī)資源,會(huì)發(fā)生什么情況?

    顯然,兩個(gè)進(jìn)程并發(fā)運(yùn)行,導(dǎo)致打印機(jī)設(shè)備交替的收到 WPS 和 Word 兩個(gè)進(jìn)程發(fā)來的打印請求,結(jié)果兩篇論文的內(nèi)容混雜在一起了。

    進(jìn)程互斥(mutual exclusion)就是用來解決這個(gè)問題的。當(dāng)某個(gè)進(jìn)程 A 在訪問打印機(jī)時(shí),如果另一個(gè)進(jìn)程 B 也想要訪問打印機(jī),它就必須等待,直到 A 進(jìn)程訪問結(jié)束并釋放打印機(jī)資源后,B 進(jìn)程才能去訪問。

    實(shí)際上,像上述的打印機(jī)這種「在一個(gè)時(shí)間段內(nèi)只允許一個(gè)進(jìn)程使用的資源」(這也就是互斥的意思),我們將其稱為「臨界資源」,對臨界資源進(jìn)行訪問的那段代碼稱為「臨界區(qū)」。

    通俗的對比一下進(jìn)程互斥和進(jìn)程同步:

    • 進(jìn)程同步:進(jìn)程 A 應(yīng)在進(jìn)程 B 之前執(zhí)行
    • 進(jìn)程互斥:進(jìn)程 A 和進(jìn)程 B 不能在同一時(shí)刻執(zhí)行

    從上不難看出,「進(jìn)程互斥是一種特殊的進(jìn)程同步」,即逐次使用臨界資源,也是對進(jìn)程使用資源的先后執(zhí)行次序的一種協(xié)調(diào)。

    3. 常見的進(jìn)程同步與互斥機(jī)制

    常見的進(jìn)程同步與互斥機(jī)制有兩種:

    • 信號量與 PV 操作
    • 管程

    ① 信號量與 PV 操作

    ?

    包交包會(huì)!看完下面這段解釋你絕對能夠明白 PV 操作是啥。

    ?

    1965年,荷蘭學(xué)者 Dijkstra 提出了一種卓有成效的實(shí)現(xiàn)進(jìn)程同步和互斥的方法 — 信號量機(jī)制(Semaphore)。信號量其實(shí)就是一個(gè)變量 ,我們可以用一個(gè)信號量來表示系統(tǒng)中某種資源的數(shù)量,比如:系統(tǒng)中只有一臺打印機(jī),就可以設(shè)置一個(gè)初值為 1 的信號量。

    用戶進(jìn)程可以通過使用操作系統(tǒng)提供的一對原語來對信號量進(jìn)行操作,從而很方便的實(shí)現(xiàn)進(jìn)程互斥或同步。這一對原語就是 PV 操作:

    1)「P 操作」:將信號量值減 1,表示「申請占用一個(gè)資源」。如果結(jié)果小于 0,表示已經(jīng)沒有可用資源,則執(zhí)行 P 操作的進(jìn)程被阻塞。如果結(jié)果大于等于 0,表示現(xiàn)有的資源足夠你使用,則執(zhí)行 P 操作的進(jìn)程繼續(xù)執(zhí)行。

    可以這么理解,當(dāng)信號量的值為 2 的時(shí)候,表示有 2 個(gè)資源可以使用,當(dāng)信號量的值為 -2 的時(shí)候,表示有兩個(gè)進(jìn)程正在等待使用這個(gè)資源。不看這句話真的無法理解 V 操作,看完頓時(shí)如夢初醒。

    2)「V 操作」:將信號量值加 1,表示「釋放一個(gè)資源」,即使用完資源后歸還資源。若加完后信號量的值小于等于 0,表示有某些進(jìn)程正在等待該資源,由于我們已經(jīng)釋放出一個(gè)資源了,因此需要喚醒一個(gè)等待使用該資源(就緒態(tài))的進(jìn)程,使之運(yùn)行下去。

    我覺得已經(jīng)講的足夠通俗了,不過對于 V 操作大家可能仍然有困惑,下面再來看兩個(gè)關(guān)于 V 操作的問答:

    問:「信號量的值 大于 0 表示有臨界資源可供使用,這個(gè)時(shí)候?yàn)槭裁床恍枰獑拘堰M(jìn)程」?

    答:所謂喚醒進(jìn)程是從就緒隊(duì)列(阻塞隊(duì)列)中喚醒進(jìn)程,而信號量的值大于 0 表示有臨界資源可供使用,也就是說這個(gè)時(shí)候沒有進(jìn)程被阻塞在這個(gè)資源上,所以不需要喚醒,正常運(yùn)行即可。

    問:「信號量的值 等于 0 的時(shí)候表示沒有臨界資源可供使用,為什么還要喚醒進(jìn)程」?

    答:V 操作是先執(zhí)行信號量值加 1 的,也就是說,把信號量的值加 1 后才變成了 0,在此之前,信號量的值是 -1,即有一個(gè)進(jìn)程正在等待這個(gè)臨界資源,我們需要喚醒它。

    信號量和 PV 操作具體的定義如下:

    實(shí)現(xiàn)進(jìn)程互斥

    兩步走即可實(shí)現(xiàn)進(jìn)程的互斥:

    • 定義一個(gè)互斥信號量,并初始化為 1
    • 把對于臨界資源的訪問置于 P 操作和 V 操作之間

    「P 操作和 V 操作必須成對出現(xiàn)」。缺少 P 操作就不能保證對臨界資源的互斥訪問,缺少 V 操作就會(huì)導(dǎo)致臨界資源永遠(yuǎn)得不到釋放、處于等待態(tài)的進(jìn)程永遠(yuǎn)得不到喚醒。

    實(shí)現(xiàn)進(jìn)程同步

    回顧一下進(jìn)程同步,就是要各并發(fā)進(jìn)程按要求有序地運(yùn)行。

    舉個(gè)例子,以下兩個(gè)進(jìn)程 P1、P2 并發(fā)執(zhí)行,由于存在異步性,因此二者交替推進(jìn)的次序是不確定的。假設(shè) P2 的 “代碼4” 要基于 P1 的 “代碼1” 和 “代碼2” 的運(yùn)行結(jié)果才能執(zhí)行,那么我們就必須保證 “代碼4” 一定是在 “代碼2” 之后才會(huì)執(zhí)行。

    如果 P2 的 “代碼4” 要基于 P1 的 “代碼1” 和 “代碼2” 的運(yùn)行結(jié)果才能執(zhí)行,那么我們就必須保證 “代碼4” 一定是在 “代碼2” 之后才會(huì)執(zhí)行。

    使用信號量和 PV 操作實(shí)現(xiàn)進(jìn)程的同步也非常方便,三步走:

    • 定義一個(gè)同步信號量,并初始化為當(dāng)前可用資源的數(shù)量
    • 在優(yōu)先級較「高」的操作的「后」面執(zhí)行 V 操作,釋放資源
    • 在優(yōu)先級較「低」的操作的「前」面執(zhí)行 P 操作,申請占用資源

    配合下面這張圖直觀理解下:

    生產(chǎn)者和消費(fèi)者問題

    下面我們利用信號量和 PV 操作來解決經(jīng)典的進(jìn)程同步和互斥問題:生產(chǎn)者和消費(fèi)者問題。

    【問題描述】:系統(tǒng)中有一組生產(chǎn)者進(jìn)程和一組消費(fèi)者進(jìn)程,生產(chǎn)者進(jìn)程每次生產(chǎn)一個(gè)產(chǎn)品放入緩沖區(qū),消費(fèi)者進(jìn)程每次從緩沖區(qū)中取出一個(gè)產(chǎn)品并使用。任何時(shí)刻,只能有一個(gè)生產(chǎn)者或消費(fèi)者可以訪問緩沖區(qū)。

    由題可知,生產(chǎn)者、消費(fèi)者共享一個(gè)初始為空、大小為 n 的緩沖區(qū),我們從題目中提煉出同步與互斥關(guān)系:

    • 同步關(guān)系 1:只有緩沖區(qū)沒滿時(shí)(優(yōu)先級高),生產(chǎn)者才能把產(chǎn)品放入緩沖區(qū)(優(yōu)先級低),否則必須等待
    • 同步關(guān)系 2:只有緩沖區(qū)不空時(shí)(優(yōu)先級高),消費(fèi)者才能從中取出產(chǎn)品(優(yōu)先級低),否則必須等待
    • 互斥關(guān)系:緩沖區(qū)是臨界資源,各進(jìn)程必須互斥地訪問。

    既然這個(gè)題目有兩個(gè)同步關(guān)系和一個(gè)互斥關(guān)系,那么我們就需要兩個(gè)同步信號量和一個(gè)互斥信號量:

    • empty:同步信號量(對應(yīng)同步關(guān)系 1),表示生產(chǎn)者還能生產(chǎn)多少,即還能放入緩沖區(qū)多少產(chǎn)品,該數(shù)量小于等于 0,則生產(chǎn)者不能進(jìn)行生產(chǎn)。初始化為 n。
    • full:同步信號量(對應(yīng)同步關(guān)系 2),表示消費(fèi)者還能從緩沖區(qū)取出多少,即當(dāng)前緩沖區(qū)已有產(chǎn)品的數(shù)量,該數(shù)量小于等于 0,則消費(fèi)者不能進(jìn)行讀取。初始化為 0。
    • mutex:互斥信號量,實(shí)現(xiàn)對緩沖區(qū)的互斥訪問。初始化為 1。

    代碼如下,注意各個(gè) PV 操作的配對:

    ② 管程

    管程有一個(gè)重要特性:「在一個(gè)時(shí)刻只能有一個(gè)進(jìn)程使用管程」。進(jìn)程在無法繼續(xù)執(zhí)行的時(shí)候不能一直占用管程,否則其它進(jìn)程將永遠(yuǎn)不能使用管程。也就是說「管程天生支持進(jìn)程互斥」

    其實(shí)使用管程是能夠?qū)崿F(xiàn)信號量的,并且也能用信號量實(shí)現(xiàn)管程。但是管程封裝的比較好,相比起信號量來需要我們編寫的代碼更少,更加易用,這也就是 「Java 采用管程機(jī)制」的原因,synchronized 關(guān)鍵字及 wait()、notify()notifyAll() 這三個(gè)方法都是管程的組成部分。把管程翻譯為 Java 領(lǐng)域的語言,就是管理類的成員變量和成員方法,讓這個(gè)類是線程安全的。再詳細(xì)的部分就不再深究了,溜了溜了。



    ?? 點(diǎn)擊下方卡片關(guān)注公眾號「飛天小牛肉」(專注于分享計(jì)算機(jī)基礎(chǔ)、Java 基礎(chǔ)和面試指南的相關(guān)原創(chuàng)技術(shù)好文,幫助讀者快速掌握高頻重點(diǎn)知識,有的放矢),與小牛肉一起成長、共同進(jìn)步 

    ?? 并向大家強(qiáng)烈推薦我維護(hù)的 Gitee 倉庫 「CS-Wiki」(Gitee 推薦項(xiàng)目,目前已 1.0k+ star。致力打造完善的后端知識體系,在技術(shù)的路上少走彎路。相比公眾號,該倉庫擁有更健全的知識體系,歡迎給位小伙伴前來交流學(xué)習(xí),倉庫地址 https://gitee.com/veal98/CS-Wiki。也可直接下方掃碼訪問


    原創(chuàng)不易,讀完有收獲不妨點(diǎn)贊|分享|在看支持

    瀏覽 46
    點(diǎn)贊
    評論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評論
    圖片
    表情
    推薦
    點(diǎn)贊
    評論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    日韩成人一级片 | 国产伦精品一区二区三区竹菊视频 | 日本国产欧美 | www.大香蕉伊人 | 操一操干一干 |