操做系統——進程,線程,鎖

基本概念

狀態、地址空間

  1. 三種基本狀態 —— 就緒、運行、阻塞

  1. 進程控制塊PCB(Process Control Block)node

    1. 進程描述信息(如PID);
    2. 進程控制&管理信息(狀態、優先級等);
    3. 源分配清單(地址空間情況、fd等);
    4. 處理其相關信息(各寄存器的值等)

進程存在的標識,在Linux系統中是task_struct,task_struct在內核棧(Linux進程氛圍用戶棧和內核棧)的尾端分配。mysql

  1. 進程地址空間

從低地址到高地址:程序員

  • text 代碼段 —— 代碼段,通常是隻讀的區域;
  • static_data 段 =
  • stack 棧區 —— 局部變量,函數的參數,返回值等,由編譯器自動分配釋放;
  • heap 堆區 —— 動態內存分配,由程序員分配釋放;
    image
  1. 進程與線程

進程是擁有資源的基本單位,進程的地址空間相互獨立;web

線程是獨立調度的基本單位,共享同一個進程內的資源(線程有本身的棧),減小了程序併發時所付出的時空開銷,而且能夠高效的共享數據,有效地利用多處理器和多核計算機,提升os的併發度。算法

一個進程異常退出不會引發另外的進程運行異常;可是線程若異常退出通常是會引發整個進程奔潰。sql

建立/撤銷/切換 進程的開銷遠大於線程的(建立線程比建立進程快10~100倍 UNPv2/P406)。數據庫

  1. 殭屍、孤兒、守護

孤兒進程 —— 父進程退出,而它的一個或多個子進程還在運行,那麼那些子進程將成爲孤兒進程。孤兒進程將被init進程(進程號爲1)所收養,並由init進程對它們完成狀態收集工做。安全

殭屍進程 —— 一個進程使用fork建立子進程,若是子進程退出,而父進程並無調用wait或waitpid獲取子進程的狀態信息,那麼子進程的進程描述符仍然保存在系統中。服務器

守護進程 —— 守護進程的父進程是init進程,由於它真正的父進程在fork出子進程後就先於子進程exit退出了,因此它是一個由init繼承的孤兒進程。不須要用戶輸入就能運行並且提供某種服務,不是對整個系統就是對某個用戶程序提供服務。常見的守護進程包括系統日誌進程syslogd、 web服務器httpd、郵件服務器sendmail和數據庫服務器mysqld等。網絡

最大進程數以及單進程內的最大線程數?

最大進程數受如下3方面限制:

  1. 不能超過pid_t類型的最大值
  2. 使用命令ulimit -u查看系統中限制的最大進程數。/etc/security/limits.conf裏面是硬限制,ulimit -u是軟限制,內核參數kernel.pid_max也作了限制。
  3. 受系統資源限制,建立一個新進程會消耗系統資源,最主要的就是內存。

IPC (interprocess communication)

UNP 分了如下幾中形式的IPC:

  • 消息傳遞 —— 管道、FIFO、消息隊列
  • 共享內存
  • 同步 ——信號量、互斥量、條件變量、讀寫鎖、文件和記錄鎖、
  • 遠程過程調用 —— solaris 門、Sun RPC
  • 跨網絡 IPC —— 套接字
  • 域套接字
  • 信號

進程間通訊方式:匿名管道,有名管道,消息隊列,共享內存,信號量,套接字,域套接字,信號

線程同步方式:互斥量,條件變量,讀寫鎖

進程間通訊

匿名管道

半雙工的(即數據只能在一個方向上流動),具備固定的讀端和寫端;是一種特殊的文件(pipefs,掛載在內核中),有固定大小,只存在於內存中;

實現原理:

管道是由內核管理的一個緩衝區,被設計成爲環形的數據結構,以便管道能夠被循環利用。當管道中沒有信息的話,從管道中讀取的進程會等待,直到另外一端的進程放入信息。當管道被放滿信息的時候,嘗試放入信息的進程會等待,直到另外一端的進程取出信息。當兩個進程都終結的時候,管道也自動消失。

在 Linux 中,管道的實現藉助了文件系統的file結構和VFS的索引節點inode。經過將兩個file結構指向同一個臨時的VFS索引節點,而這個VFS索引節點又指向一個物理頁面而實現的。

內核會利用必定的機制同步對管道的訪問。
image

有名管道

半雙工,可在無關進程使用;FIFO有路徑名與之相關聯,以一種特殊設備文件形式存在於文件系統中

實現原理:

Linux中設立了一個專門的特殊文件系統--管道文件,FIFO在文件系統中有對應的路徑。當一個進程以讀(r)的方式打開該文件,而另外一個進程以寫(w)的方式打開該文件,那麼內核就會在這兩個進程之間創建管道,雖然FIFO在VFS的目錄樹下可見,可是它並不對應disk上的文件。
本質上是一個先進先出的隊列數據結構,最先放入的數據被最早讀出來,從而保證信息交流的順序。FIFO只是借用了文件系統來爲管道命名。當刪除FIFO文件時,管道鏈接也隨之消失。當進程終止時,管道內的數據會被刪除。

消息隊列

  1. 面向記錄的,其中的消息具備特定的格式以及特定的優先級;
  2. 獨立於發送與接收進程。進程終止時,消息隊列及其內容並不會被刪除(隨內核的持性)。
  3. 能夠實現消息的隨機查詢,不必定要以先進先出的次序讀取,也能夠按消息的類型讀取。
爲何不使用消息隊列
  1. 進程終止時,消息隊列及其內容並不會被刪除(隨內核的持性)。
  2. 在文件系統中沒有名字,不能使用IO。

共享內存和信號量

共享內存是最快的:

一般往管道、FIFO或消息隊列寫入數據時,這些IPC須要將數據從進程複製到內核,一般總共須要複製4次,而共享內存則只拷貝2次數據;如圖:
image
image

信號(Signal)

用於通知接收進程,有某種事件發生。

信號是在軟件層次上對中斷機制的一種模擬,在原理上,一個進程收到一個信號與處理器收到一箇中斷請求能夠說是同樣的。信號是異步的,一個進程沒必要經過任何操做來等待信號的到達。

  • SIGRTMIN以前的信號是非排隊(不可靠)的,屢次連續發生的相同信號,只遞交一次;SIGRTMIN以後的信號不會丟失,會遞交屢次。
  • 在信號處理函數
    • singal:只阻塞當前正在處理的信號,後續信號會排隊(也會區分可靠和不可靠)
    • sigaction:能夠設置阻塞正在處理的信號和其餘型號

Pipe 與 FIFO 比較:

  1. pipe在特殊文件系統pipefs中(內核中),VFS 目錄樹下不可見;FIFO 在目錄樹下可見;
  2. 都有 inode,但沒有磁盤鏡像(disk image);
  3. Pipe 用於親緣關係進程通訊;FIFO 無此要求;
  4. 限制都包含兩個:OPEN_MAX(一個進程在任意時刻打開的最大描述符,默認1024);還有PIPE_BUF(可原子性地往一個管道/FIFO 的最大數據量,默認 4K)

線程間同步

互斥鎖(Mutex)

加鎖原語,排他性訪問共享數據,用於保護臨界區。可細分爲遞歸鎖/非遞歸鎖。
若是存在某個線程依然使用原先的程序

(即不嘗試得到mutex,而直接修改共享變量),互斥鎖不能阻止其修改。因此,互斥鎖機制須要程序員本身來寫出完善的程序來實現互斥鎖的功能(如下鎖 同樣)。

image

條件變量(Condition Variable)

互斥鎖用於上鎖,條件變量用於等待,條件變量的使用是與互斥鎖共通使用的。

條件變量學名叫管程(monitor)【From muduo P40】。

image

讀寫鎖

讀寫鎖也叫作 共享-獨佔鎖,容許更高的併發度。

互斥量要麼是鎖住狀態,要麼是不加鎖狀態,並且一次只有一個線程對其加鎖。
讀寫鎖能夠有三種狀態:讀模式下加鎖狀態,寫模式下加鎖狀態,不加鎖狀態。一次只有一個線程能夠佔有寫模式的讀寫鎖,可是多個線程可用同時佔有讀模式的讀寫鎖。

image

讀寫鎖能夠經過使用互斥鎖和條件變量來實現。

自旋鎖(spinlock)

在獲取鎖以前一直處於忙等(自旋)阻塞狀態;經常使用於
鎖被持有的時間短,且線程並不但願在從新調度上花費太多成本。當線程自旋等待鎖變爲可用時,CPU不能作其餘事情。

故而自旋鎖常做爲底層原語,用於實現其餘類型的鎖。

記錄鎖

記錄鎖是讀寫鎖的一種擴展類型,可用於親緣關係或無親緣關係的進程之間共享某個文件的讀與寫。被鎖住的文件經過文件描述符進行訪問,執行上鎖的操做函數是fcntl,這種類型的鎖一般在內核中維護。

記錄鎖的功能是:一個進程正在讀或修改文件的某個部分時,能夠阻止其餘進程修改同一文件區,即其鎖定的是文件的一個區域或整個文件。

記錄鎖有兩種類型:共享讀鎖,獨佔寫鎖。基本規則是:多個進程在一個給定的字節上能夠有一把共享的讀鎖,但在一個給定字節上的寫鎖只能有一個進程獨用。即:若是在一個給定的字節上已經有一把讀或多把讀鎖,則不能在該字節上再加寫鎖;若是在一個字節上已經有一把獨佔性的寫鎖,則不能再對它加任何讀鎖。

死鎖

  1. 死鎖 —— 就是兩個或多個進程被無限期地阻塞、相互等待的一種狀態。
  2. 死鎖的四個條件
    1. 競爭同一個資源
    2. 持有資源不釋放
    3. 不能搶佔資源
    4. 循環使用資源

處理死鎖的策略:
通常來講,打破循環使用資源最容易,即順序加減鎖

image
銀行家算法(死鎖避免算法)。在資源動態分配過程當中,防止系統進入不安全狀態,以免發生死鎖。

數據庫中會用到等待圖進行死鎖檢測

  1. 死鎖定理:
    經過將資源分配圖簡化的方法,來檢測系統狀態是否爲死鎖狀態。
    當且僅當S狀態的資源分配圖不可徹底簡化時,S爲死鎖狀態。

經典問題

  1. 生產者-消費者問題
  2. 讀者-寫者問題

Futex

在Linux下,信號量和線程互斥鎖的實現都是經過futex系統調用。

相關文章
相關標籤/搜索