日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

备战秋招——操作系统

發布時間:2024/4/15 windows 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 备战秋招——操作系统 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

進程與線程:

概念:

線程:是操作系統能夠進行運算調度的最小單位。是進程中的一個執行流程,一個進程中可以運行多個線程。

進程:一個執行中的程序的實例

?

進程 與 線程 的區別

進程在執行過程中擁有獨立的內存單元,而多個線程共享內存

進程和線程的主要差別在于它們是不同的操作系統資源管理方式。進程有獨立的地址空間,一個進程崩潰后,在保護模式下不會對其它進程產生影響,而線程只是一個進程中的不同執行路徑。線程有自己的堆棧和局部變量,但線程之間沒有單獨的地址空間,一個線程死掉就等于整個進程死掉,所以多進程的程序要比多線程的程序健壯,但在進程切換時,耗費資源較大,效率要差一些。但對于一些要求同時進行并且又要共享某些變量的并發操作,只能用線程,不能用進程。

?

進程在執行過程中擁有獨立的內存單元,而多個線程共享進程的內存。(資源分配給進程,同一進程的所有線程共享該進程的所有資源。同一進程中的多個線程共享代碼段(代碼和常量),數據段(全局變量和靜態變量),擴展段(堆存儲)。但是每個線程擁有自己的棧段,棧段又叫運行時段,用來存放所有局部變量和臨時變量。

進程是資源分配的最小單位,線程是CPU調度的最小單位;

系統開銷: 由于在創建或撤消進程時,系統都要為之分配或回收資源,如內存空間、I/o設備等。因此,操作系統所付出的開銷將顯著地大于在創建或撤消線程時的開銷。類似地,在進行進程切換時,涉及到整個當前進程CPU環境的保存以及新被調度運行的進程的CPU環境的設置。而線程切換只須保存和設置少量寄存器的內容,并不涉及存儲器管理方面的操作。可見,進程切換的開銷也遠大于線程切換的開銷。

通信:由于同一進程中的多個線程具有相同的地址空間,致使它們之間的同步和通信的實現,也變得比較容易。進程間通信IPC,線程間可以直接讀寫進程數據段(如全局變量)來進行通信——需要進程同步和互斥手段的輔助,以保證數據的一致性。在有的系統中,線程的切換、同步和通信都無須操作系統內核的干預

進程間不會相互影響 ;線程一個線程掛掉將導致整個進程掛掉

?

進程間通信

在 linux 下進程間通信的幾種主要手段簡介:

  • 管道(Pipe)及有名管道(named pipe):管道:傳輸資源。本質上是內核的一塊緩沖區。(特性:半雙工,單向通信)。 Linux一切皆文件,操作系統為管道提供操作的方法:文件操作。管道可用于具有親緣關系進程間的通信,有名管道克服了管道沒有名字的限制,因此,除具有管道所具有的功能外,它還允許無親緣關系進程間的通信;

  • 信號(Signal):信號是比較復雜的通信方式,用于通知接受進程有某種事件發生,除了用于進程間通信外,進程還可以發送信號給進程本身;linux除了支持Unix早期信號語義函數sigal外,還支持語義符合Posix.1標準的信號函數sigaction(實際上,該函數是基于BSD的,BSD為了實現可靠信號機制,又能夠統一對外接口,用sigaction函數重新實現了signal函數);
  • 消息隊列(Message)

    消息隊列實際上是操作系統在內核為我們創建的一個隊列,通過這個隊列的標識符key,每一個進程都可以打開這個隊列,每個進程都可以通過這個隊列向這個隊列中插入一個結點或者獲取一個結點來完成不同進程間的通信。
    用戶組織一個帶有類型的數據塊,添加到隊列中,其他的進程從隊列中獲取數據塊,即消息隊列發送的是一個帶有類型的數據塊;消息隊列是一個全雙工通信,可讀可寫(可以發送數據,也可以接受數據)

    消息隊列是消息的鏈接表,包括Posix消息隊列system V消息隊列。有足夠權限的進程可以向隊列中添加消息,被賦予讀權限的進程則可以讀走隊列中的消息。消息隊列克服了信號承載信息量少,管道只能承載無格式字節流以及緩沖區大小受限等缺點。

  • ** 共享內存**:使得多個進程可以訪問同一塊內存空間,是最快的可用IPC形式。是針對其他通信機制運行效率較低而設計的。往往與其它通信機制,如信號量結合使用,來達到進程間的同步及互斥。

  • 信號量(semaphore):主要作為進程間以及同一進程不同線程之間的同步手段。

  • 套接口(Socket):更為一般的進程間通信機制,可用于不同機器之間的進程間通信。起初是由Unix系統的BSD分支開發出來的,但現在一般可以移植到其它類Unix系統上:Linux和System V的變種都支持套接字。

  • 各種通信方式的比較和優缺點:

  • 管道:速度慢,容量有限,只有父子進程能通訊

  • 有名管道(named pipe):任何進程間都能通訊,但速度慢

  • 消息隊列:容量受到系統限制,且要注意第一次讀的時候,要考慮上一次沒有讀完數據的問題

  • 信號量:不能傳遞復雜消息,只能用來同步

  • 共享內存:能夠很容易控制容量,速度快,但要保持同步,比如一個進程在寫的時候,另一個進程要注意讀寫的問題,相當于線程中的線程安全,當然,共享內存區同樣可以用作線程間通訊,不過沒這個必要,線程間本來就已經共享了同一進程內的一塊內存

  • 進程間通信主要包括管道、系統IPC(包括消息隊列、信號量、信號、共享內存等)、以及套接字socket。

    1.管道:

    管道主要包括無名管道和命名管道:管道可用于具有親緣關系的父子進程間的通信,有名管道除了具有管道所具有的功能外,它還允許無親緣關系進程間的通信

    1.1 普通管道PIPE:

    1)它是半雙工的(即數據只能在一個方向上流動),具有固定的讀端和寫端

    2)它只能用于具有親緣關系的進程之間的通信(也是父子進程或者兄弟進程之間)

    3)它可以看成是一種特殊的文件,對于它的讀寫也可以使用普通的read、write等函數。但是它不是普通的文件,并不屬于其他任何文件系統,并且只存在于內存中。

    1.2 命名管道FIFO:

    1)FIFO可以在無關的進程之間交換數據

    2)FIFO有路徑名與之相關聯,它以一種特殊設備文件形式存在于文件系統中。

    ?

    2. 系統IPC:

    2.1 消息隊列

    消息隊列,是消息的鏈接表,存放在內核中。一個消息隊列由一個標識符(即隊列ID)來標記。 (消息隊列克服了信號傳遞信息少,管道只能承載無格式字節流以及緩沖區大小受限等特點)具有寫權限得進程可以按照一定得規則向消息隊列中添加新信息;對消息隊列有讀權限得進程則可以從消息隊列中讀取信息;

    特點:

    1)消息隊列是面向記錄的,其中的消息具有特定的格式以及特定的優先級。

    2)消息隊列獨立于發送與接收進程。進程終止時,消息隊列及其內容并不會被刪除。

    3)消息隊列可以實現消息的隨機查詢,消息不一定要以先進先出的次序讀取,也可以按消息的類型讀取。

    2.2 信號量semaphore

    信號量(semaphore)與已經介紹過的 IPC 結構不同,它是一個計數器,可以用來控制多個進程對共享資源的訪問。信號量用于實現進程間的互斥與同步,而不是用于存儲進程間通信數據。

    特點:

    1)信號量用于進程間同步,若要在進程間傳遞數據需要結合共享內存。

    2)信號量基于操作系統的 PV 操作,程序對信號量的操作都是原子操作。

    3)每次對信號量的 PV 操作不僅限于對信號量值加 1 或減 1,而且可以加減任意正整數。

    4)支持信號量組。

    2.3 信號signal

    信號是一種比較復雜的通信方式,用于通知接收進程某個事件已經發生。

    2.4 共享內存(Shared Memory)

    它使得多個進程可以訪問同一塊內存空間,不同進程可以及時看到對方進程中對共享內存中數據得更新。這種方式需要依靠某種同步操作,如互斥鎖和信號量等

    特點:

    1)共享內存是最快的一種IPC,因為進程是直接對內存進行存取

    2)因為多個進程可以同時操作,所以需要進行同步

    3)信號量+共享內存通常結合在一起使用,信號量用來同步對共享內存的訪問

    ?

    3. 套接字SOCKET:

    socket也是一種進程間通信機制,與其他通信機制不同的是,它可用于不同主機之間的進程通信。

    ?

    ?

    線程間通信的方式:

    1、臨界區:

    通過多線程的串行化來訪問公共資源或一段代碼,速度快,適合控制數據訪問;

    2、互斥量 Synchronized/Lock:

    采用互斥對象機制,只有擁有互斥對象的線程才有訪問公共資源的權限。因為互斥對象只有一個,所以可以保證公共資源不會被多個線程同時訪問

    3、信號量 Semphare:

    為控制具有有限數量的用戶資源而設計的,它允許多個線程在同一時刻去訪問同一個資源,但一般需要限制同一時刻訪問此資源的最大線程數目。

    4、事件(信號),Wait/Notify:

    通過通知操作的方式來保持多線程同步,還可以方便的實現多線程優先級的比較操作

    ?

    ?

    并發(concurrency)和并行(parallelism)

    并發(concurrency):指宏觀上看起來兩個程序在同時運行,比如說在單核cpu上的多任務。但是從微觀上看兩個程序的指令是交織著運行的,你的指令之間穿插著我的指令,我的指令之間穿插著你的,在單個周期內只運行了一個指令。這種并發并不能提高計算機的性能,只能提高效率。

    并行(parallelism):指嚴格物理意義上的同時運行,比如多核cpu,兩個程序分別運行在兩個核上,兩者之間互不影響,單個周期內每個程序都運行了自己的指令,也就是運行了兩條指令。這樣說來并行的確提高了計算機的效率。所以現在的cpu都是往多核方面發展。

    ?

    ?

    有了進程,為什么還要有線程?

    線程產生的原因:

    進程可以使多個程序能并發執行,以提高資源的利用率和系統的吞吐量;但是其具有一些缺點:

    進程在同一時間只能干一件事

    進程在執行的過程中如果阻塞,整個進程就會掛起,即使進程中有些工作不依賴于等待的資源,仍然不會執行。

    ?

    因此,操作系統引入了比進程粒度更小的線程,作為并發執行的基本單位,從而減少程序在并發執行時所付出的時空開銷,提高并發性。和進程相比,線程的優勢如下:

    從資源上來講,線程是一種非常"節儉"的多任務操作方式。在linux系統下,啟動一個新的進程必須分配給它獨立的地址空間,建立眾多的數據表來維護它的代碼段、堆棧段和數據段,這是一種"昂貴"的多任務工作方式。

    從切換效率上來講,運行于一個進程中的多個線程,它們之間使用相同的地址空間,而且線程間彼此切換所需時間也遠遠小于進程間切換所需要的時間。據統計,一個進程的開銷大約是一個線程開銷的30倍左右。(

    從通信機制上來講,線程間方便的通信機制。對不同進程來說,它們具有獨立的數據空間,要進行數據的傳遞只能通過進程間通信的方式進行,這種方式不僅費時,而且很不方便。線程則不然,由于同一進程下的線程之間共享數據空間,所以一個線程的數據可以直接為其他線程所用,這不僅快捷,而且方便。

    除以上優點外,多線程程序作為一種多任務、并發的工作方式,還有如下優點:

    1、使多CPU系統更加有效。操作系統會保證當線程數不大于CPU數目時,不同的線程運行于不同的CPU上。

    2、改善程序結構。一個既長又復雜的進程可以考慮分為多個線程,成為幾個獨立或半獨立的運行部分,這樣的程序才會利于理解和修改。

    ?

    ?

    多線程和多進程的不同

    進程是資源分配的最小單位,而線程時CPU調度的最小單位。多線程之間共享同一個進程的地址空間,線程間通信簡單,同步復雜,線程創建、銷毀和切換簡單,速度快,占用內存少,適用于多核分布式系統,但是線程間會相互影響,一個線程意外終止會導致同一個進程的其他線程也終止,程序可靠性弱。而多進程間擁有各自獨立的運行地址空間,進程間不會相互影響,程序可靠性強,但是進程創建、銷毀和切換復雜,速度慢,占用內存多,進程間通信復雜,但是同步簡單,適用于多核、多機分布。

    多進程和多線程的使用場景?

    多進程模型的優勢是CPU

    多線程模型主要優勢為線程間切換代價較小,因此適用于I/O密集型的工作場景,因此I/O密集型的工作場景經常會由于I/O阻塞導致頻繁的切換線程。同時,多線程模型也適用于單機多核分布式場景。

    ?

    多進程模型,適用于CPU密集型。同時,多進程模型也適用于多機分布式場景中,易于多機擴展。

    ?

    ?

    死鎖發生的條件以及如何解決死鎖

    死鎖是指兩個或兩個以上進程在執行過程中,因爭奪資源而造成的相互等待的現象。死鎖發生的四個必要條件如下:

    互斥條件:進程對所分配到的資源不允許其他進程訪問,若其他進程訪問該資源,只能等待,直至占有該資源的進程使用完成后釋放該資源;

    請求和保持條件:進程獲得一定的資源后,又對其他資源發出請求,但是該資源可能被其他進程占有,此時請求阻塞,但該進程不會釋放自己已經占有的資源

    不可剝奪條件:進程已獲得的資源,在未完成使用之前,不可被剝奪,只能在使用后自己釋放

    環路等待條件:進程發生死鎖后,必然存在一個進程-資源之間的環形鏈

    解決死鎖的方法即破壞上述四個條件之一,主要方法如下:

    資源一次性分配,從而剝奪請求和保持條件

    可剝奪資源:即當進程新的資源未得到滿足時,釋放已占有的資源,從而破壞不可剝奪的條件

    資源有序分配法:系統給每類資源賦予一個序號,每個進程按編號遞增的請求資源,釋放則相反,從而破壞環路等待的條件

    ?

    ?

    互斥鎖(mutex)機制,以及互斥鎖和讀寫鎖的區別

    1、互斥鎖和讀寫鎖區別:

    互斥鎖:mutex,用于保證在任何時刻,都只能有一個線程訪問該對象。當獲取鎖操作失敗時,線程會進入睡眠,等待鎖釋放時被喚醒。

    讀寫鎖:rwlock,分為讀鎖和寫鎖。處于讀操作時,可以允許多個線程同時獲得讀操作。但是同一時刻只能有一個線程可以獲得寫鎖。其它獲取寫鎖失敗的線程都會進入睡眠狀態,直到寫鎖釋放時被喚醒。?注意:寫鎖會阻塞其它讀寫鎖。當有一個線程獲得寫鎖在寫時,讀鎖也不能被其它線程獲取;寫者優先于讀者(一旦有寫者,則后續讀者必須等待,喚醒時優先考慮寫者)。適用于讀取數據的頻率遠遠大于寫數據的頻率的場合。

    互斥鎖和讀寫鎖的區別:

    1)讀寫鎖區分讀者和寫者,而互斥鎖不區分

    2)互斥鎖同一時間只允許一個線程訪問該對象,無論讀寫;讀寫鎖同一時間內只允許一個寫者,但是允許多個讀者同時讀對象。

    2、Linux的4種鎖機制:

    互斥鎖:mutex,用于保證在任何時刻,都只能有一個線程訪問該對象。當獲取鎖操作失敗時,線程會進入睡眠,等待鎖釋放時被喚醒

    讀寫鎖:rwlock,分為讀鎖和寫鎖。處于讀操作時,可以允許多個線程同時獲得讀操作。但是同一時刻只能有一個線程可以獲得寫鎖。其它獲取寫鎖失敗的線程都會進入睡眠狀態,直到寫鎖釋放時被喚醒。 注意:寫鎖會阻塞其它讀寫鎖。當有一個線程獲得寫鎖在寫時,讀鎖也不能被其它線程獲取;寫者優先于讀者(一旦有寫者,則后續讀者必須等待,喚醒時優先考慮寫者)。適用于讀取數據的頻率遠遠大于寫數據的頻率的場合。

    自旋鎖:spinlock,在任何時刻同樣只能有一個線程訪問對象。但是當獲取鎖操作失敗時,不會進入睡眠,而是會在原地自旋,直到鎖被釋放。這樣節省了線程從睡眠狀態到被喚醒期間的消耗,在加鎖時間短暫的環境下會極大的提高效率。但如果加鎖時間過長,則會非常浪費CPU資源。

    RCU:即read-copy-update,在修改數據時,首先需要讀取數據,然后生成一個副本,對副本進行修改。修改完成后,再將老數據update成新的數據。使用RCU時,讀者幾乎不需要同步開銷,既不需要獲得鎖,也不使用原子指令,不會導致鎖競爭,因此就不用考慮死鎖問題了。而對于寫者的同步開銷較大,它需要復制被修改的數據,還必須使用鎖機制同步并行其它寫者的修改操作。在有大量讀操作,少量寫操作的情況下效率非常高。

    ?

    ?

    A* a = new A; a->i = 10;在內核中的內存分配上發生了什么?

    1、程序內存管理:

    一個程序本質上都是由BSS段、data段、text段三個組成的。可以看到一個可執行程序在存儲(沒有調入內存)時分為代碼段、數據區和未初始化數據區三部分。

    BSS段(未初始化數據區):通常用來存放程序中未初始化的全局變量和靜態變量的一塊內存區域。BSS段屬于靜態分配,程序結束后靜態變量資源由系統自動釋放。

    數據段:存放程序中已初始化的全局變量的一塊內存區域。數據段也屬于靜態內存分配

    ?

    代碼段:存放程序執行代碼的一塊內存區域。這部分區域的大小在程序運行前就已經確定,并且內存區域屬于只讀。在代碼段中,也有可能包含一些只讀的常數變量

    ?

    text段和data段在編譯時已經分配了空間,而BSS段并不占用可執行文件的大小,它是由鏈接器來獲取內存的。

    ?

    bss段(未進行初始化的數據)的內容并不存放在磁盤上的程序文件中。其原因是內核在程序開始運行前將它們設置為0。需要存放在程序文件中的只有正文段和初始化數據段。

    ?

    data段(已經初始化的數據)則為數據分配空間,數據保存到目標文件中。

    ?

    數據段包含經過初始化的全局變量以及它們的值。BSS段的大小從可執行文件中得到,然后鏈接器得到這個大小的內存塊,緊跟在數據段的后面。當這個內存進入程序的地址空間后全部清零。包含數據段和BSS段的整個區段此時通常稱為數據區。

    ?

    可執行程序在運行時又多出兩個區域:棧區和堆區。

    ?

    棧區:由編譯器自動釋放,存放函數的參數值、局部變量等。每當一個函數被調用時,該函數的返回類型和一些調用的信息被存放到棧中。然后這個被調用的函數再為他的自動變量和臨時變量在棧上分配空間。每調用一個函數一個新的棧就會被使用。棧區是從高地址位向低地址位增長的,是一塊連續的內存區域,最大容量是由系統預先定義好的,申請的棧空間超過這個界限時會提示溢出,用戶能從棧中獲取的空間較小。

    ?

    堆區:用于動態分配內存,位于BSS和棧中間的地址區域。由程序員申請分配和釋放。堆是從低地址位向高地址位增長,采用鏈式存儲結構。頻繁的 malloc/free造成內存空間的不連續,產生碎片。當申請堆空間時庫函數是按照一定的算法搜索可用的足夠大的空間。因此堆的效率比棧要低的多。

    2、A* a = new A; a->i = 10:

    1)A *a:a是一個局部變量,類型為指針,故而操作系統在程序棧區開辟4/8字節的空間(0x000m),分配給指針a。

    2)new A:通過new動態的在堆區申請類A大小的空間(0x000n)。

    3)a = new A:將指針a的內存區域填入棧中類A申請到的地址的地址。即*(0x000m)=0x000n。

    4)a->i:先找到指針a的地址0x000m,通過a的值0x000n和i在類a中偏移offset,得到a->i的地址0x000n + offset,進行*(0x000n + offset) = 10的賦值操作,即內存0x000n + offset的值是10。

    ?

    ?

    一個類,里面有static,virtual,之類的,來說一說這個類的內存分布?

    1、static修飾符

    1)static修飾成員變量

    對于非靜態數據成員,每個類對象都有自己的拷貝。而靜態數據成員被當做是類的成員,無論這個類被定義了多少個,靜態數據成員都只有一份拷貝,為該類型的所有對象所共享(包括其派生類)。所以,靜態數據成員的值對每個對象都是一樣的,它的值可以更新。

    因為靜態數據成員在全局數據區分配內存,屬于本類的所有對象共享,所以它不屬于特定的類對象,在沒有產生類對象前就可以使用。

    2)static修飾成員函數

    與普通的成員函數相比,靜態成員函數由于不是與任何的對象相聯系,因此它不具有this指針。從這個意義上來說,它無法訪問屬于類對象的非靜態數據成員,也無法訪問非靜態成員函數,只能調用其他的靜態成員函數。

    Static修飾的成員函數,在代碼區分配內存。

    2、C++繼承和虛函數

    C++多態分為靜態多態和動態多態。靜態多態是通過重載和模板技術實現,在編譯的時候確定。動態多態通過虛函數和繼承關系來實現,執行動態綁定,在運行的時候確定。

    動態多態實現有幾個條件:

    (1)?虛函數;

    (2)?一個基類的指針或引用指向派生類的對象;

    基類指針在調用成員函數(虛函數)時,就會去查找該對象的虛函數表。虛函數表的地址在每個對象的首地址。查找該虛函數表中該函數的指針進行調用。

    每個對象中保存的只是一個虛函數表的指針,C++內部為每一個類維持一個虛函數表,該類的對象的都指向這同一個虛函數表。

    虛函數表中為什么就能準確查找相應的函數指針呢?因為在類設計的時候,虛函數表直接從基類也繼承過來,如果覆蓋了其中的某個虛函數,那么虛函數表的指針就會被替換,因此可以根據指針準確找到該調用哪個函數。

    3、virtual修飾符

    如果一個類是局部變量則該類數據存儲在棧區,如果一個類是通過new/malloc動態申請的,則該類數據存儲在堆區。

    如果該類是virutal繼承而來的子類,則該類的虛函數表指針和該類其他成員一起存儲。虛函數表指針指向只讀數據段中的類虛函數表,虛函數表中存放著一個個函數指針,函數指針指向代碼段中的具體函數。

    如果類中成員是virtual屬性,會隱藏父類對應的屬性。

    ?

    ?

    軟鏈接和硬鏈接區別

    為了解決文件共享問題,Linux引入了軟鏈接和硬鏈接。除了為Linux解決文件共享使用,還帶來了隱藏文件路徑、增加權限安全及節省存儲等好處。若1個inode號對應多個文件名,則為硬鏈接,即硬鏈接就是同一個文件使用了不同的別名,使用ln創建。若文件用戶數據塊中存放的內容是另一個文件的路徑名指向,則該文件是軟連接。軟連接是一個普通文件,有自己獨立的inode,但是其數據塊內容比較特殊。

    ?

    ?

    用戶態和內核態區別

    用戶態和內核態是操作系統的兩種運行級別,兩者最大的區別就是特權級不同。用戶態擁有最低的特權級,內核態擁有較高的特權級。運行在用戶態的程序不能直接訪問操作系統內核數據結構和程序。內核態和用戶態之間的轉換方式主要包括:系統調用,異常和中斷。

    協程

    協程是一種用戶態的輕量級線程,協程的調度完全由用戶控制。從技術的角度來說,“協程就是你可以暫停執行的函數”。協程擁有自己的寄存器上下文和棧。協程調度切換時,將寄存器上下文和棧保存到其他地方,在切回來的時候,恢復先前保存的寄存器上下文和棧,直接操作棧則基本沒有內核切換的開銷,可以不加鎖的訪問全局變量,所以上下文的切換非常快。

    協程和進程線程的區別

    1) 一個線程可以多個協程,一個進程也可以單獨擁有多個協程。

    2) 線程進程都是同步機制,而協程則是異步

    3)?協程能保留上一次調用時的狀態,每次過程重入時,就相當于進入上一次調用的狀態。

    4)線程是搶占式,而協程是非搶占式的,所以需要用戶自己釋放使用權來切換到其他協程,因此同一時間其實只有一個協程擁有運行權,相當于單線程的能力。

    5)協程并不是取代線程, 而且抽象于線程之上, 線程是被分割的CPU資源, 協程是組織好的代碼流程, 協程需要線程來承載運行, 線程是協程的資源, 但協程不會直接使用線程, 協程直接利用的是執行器(Interceptor), 執行器可以關聯任意線程或線程池, 可以使當前線程, UI線程, 或新建新程.。

    6)線程是協程的資源。協程通過Interceptor來間接使用線程這個資源。

    ?

    ?

    IO多路復用(IO multiplexing)

    ?IO multiplexing這個詞可能有點陌生,但是如果我說select/epoll,大概就都能明白了。有些地方也稱這種IO方式為事件驅動IO(event driven IO)。我們都知道,select/epoll的好處就在于單個process就可以同時處理多個網絡連接的IO。它的基本原理就是select/epoll這個function會不斷的輪詢所負責的所有socket,當某個socket有數據到達了,就通知用戶進程。它的流程如圖:

    ?

    當用戶進程調用了select,那么整個進程會被block,而同時,kernel會“監視”所有select負責的socket,當任何一個socket中的數據準備好了,select就會返回。這個時候用戶進程再調用read操作,將數據從kernel拷貝到用戶進程。
    ??? 這個圖和blocking IO的圖其實并沒有太大的不同,事實上還更差一些。因為這里需要使用兩個系統調用(select和recvfrom),而blocking IO只調用了一個系統調用(recvfrom)。但是,用select的優勢在于它可以同時處理多個connection。

    ? ? 強調:

    ? ? 1. 如果處理的連接數不是很高的話,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延遲還更大。select/epoll的優勢并不是對于單個連接能處理得更快,而是在于能處理更多的連接。

    ? ? 2.?在多路復用模型中,對于每一個socket,一般都設置成為non-blocking,但是,如上圖所示,整個用戶的process其實是一直被block的。只不過process是被select這個函數block,而不是被socket IO給block。

    ? ??結論: select的優勢在于可以處理多個連接,不適用于單個連接?

    ?

    ?

    ?

    (1)select==>時間復雜度O(n)

    它僅僅知道了,有I/O事件發生了,卻并不知道是哪那幾個流(可能有一個,多個,甚至全部),我們只能無差別輪詢所有流,找出能讀出數據,或者寫入數據的流,對他們進行操作。所以select具有O(n)的無差別輪詢復雜度,同時處理的流越多,無差別輪詢時間就越長。

    (2)poll==>時間復雜度O(n)

    poll本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,然后查詢每個fd對應的設備狀態,?但是它沒有最大連接數的限制,原因是它是基于鏈表來存儲的.

    (3)epoll==>時間復雜度O(1)

    epoll可以理解為event poll,不同于忙輪詢和無差別輪詢,epoll會把哪個流發生了怎樣的I/O事件通知我們。所以我們說epoll實際上是事件驅動(每個事件關聯上fd)的,此時我們對這些流的操作都是有意義的。(復雜度降低到了O(1))

    ?

    ?int epoll_create(int size);?
    ?int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);?
    ?int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);?

    ?

    epoll的高效就在于,當我們調用epoll_ctl往里塞入百萬個句柄時,epoll_wait仍然可以飛快的返回,并有效的將發生事件的句柄給我們用戶。這是由于我們在調用epoll_create時,內核除了幫我們在epoll文件系統里建了個file結點,在內核cache里建了個紅黑樹用于存儲以后epoll_ctl傳來的socket外,還會再建立一個list鏈表,用于存儲準備就緒的事件,當epoll_wait調用時,僅僅觀察這個list鏈表里有沒有數據即可。有數據就返回,沒有數據就sleep,等到timeout時間到后即使鏈表沒數據也返回。所以,epoll_wait非常高效。 那么,這個準備就緒list鏈表是怎么維護的呢?當我們執行epoll_ctl時,除了把socket放到epoll文件系統里file對象對應的紅黑樹上之外,還會給內核中斷處理程序注冊一個回調函數,告訴內核,如果這個句柄的中斷到了,就把它放到準備就緒list鏈表里。所以,當一個socket上有數據到了,內核在把網卡上的數據copy到內核中后就來把socket插入到準備就緒鏈表里了。 如此,一顆紅黑樹,一張準備就緒句柄鏈表,少量的內核cache,就幫我們解決了大并發下的socket處理問題。執行epoll_create時,創建了紅黑樹和就緒鏈表,執行epoll_ctl時,如果增加socket句柄,則檢查在紅黑樹中是否存在,存在立即返回,不存在則添加到樹干上,然后向內核注冊回調函數,用于當中斷事件來臨時向準備就緒鏈表中插入數據。執行epoll_wait時立刻返回準備就緒鏈表里的數據即可。

    ?

    ?

    ?

    ?

    mmap

    mmap是一種內存映射文件的方法,即將一個文件或者其它對象映射到進程的地址空間,實現文件磁盤地址和進程虛擬地址空間中一段虛擬地址的一一對映關系。實現這樣的映射關系后,進程就可以采用指針的方式讀寫操作這一段內存,而系統會自動回寫臟頁面到對應的文件磁盤上,即完成了對文件的操作而不必再調用read,write等系統調用函數。相反,內核空間對這段區域的修改也直接反映用戶空間,從而可以實現不同進程間的文件共享。如下圖所示:

    ?

    占坑待補?

    ?

    ?

    MD5應用

    MD5的典型應用是對一段信息(Message)產生信息摘要(Message-Digest),以防止被篡改。

    MD5將整個文件當作一個大文本信息,通過其不可逆的字符串變換算法,產生了這個唯一的MD5信息摘要。

    MD5就可以為任何文件(不管其大小、格式、數量)產生一個同樣獨一無二的“數字指紋”,如果任何人對文件做了任何改動,其MD5值也就是對應的“數字指紋”都會發生變化。

    MD5實際上是一種有損壓縮技術,壓縮前文件一樣MD5值一定一樣,反之MD5值一樣并不能保證壓縮前的數據是一樣的。在密碼學上發生這樣的概率是很小的,所以MD5在密碼加密領域有一席之地。但是專業的黑客甚至普通黑客也可以利用MD5值,實際是有損壓縮技術這一原理,將MD5的逆運算的值作為一張表俗稱彩虹表的散列表來破解密碼。

    ?

    ?

    ?

    ?

    ?

    ?

    轉載于:https://www.cnblogs.com/DSKer/p/10932739.html

    總結

    以上是生活随笔為你收集整理的备战秋招——操作系统的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。