1. 程式人生 > >linux下多種鎖的比較

linux下多種鎖的比較

最近研究MySQL原始碼,各種鎖,各種互斥,好在我去年認真學了《unix環境高階程式設計》, 雖然已經忘得差不多了,但是學過始終是學過,拿起來也快。寫這篇文章的目的就是總結Linux 下多執行緒程式設計,作為日後的參考資料。

本文將介紹linux系統下多執行緒程式設計中,執行緒同步的各種方法。包括:

在介紹不同的執行緒同步的方法之前,先簡單的介紹一下程序和執行緒的概念, 它們的優缺點,執行緒相關的API,讀者——寫者問題和哲學家就餐問題。

基礎知識

1. 程序和執行緒

程序(process)是指在系統中正在執行的一個應用程式,是系統資源分配的基本單位,在記憶體 中有其完備的資料空間和程式碼空間,擁有完整的虛擬空間地址。一個程序所擁有的資料和變數只 屬於它自己。

執行緒(thread)是程序內相對獨立的可執行單元,所以也被稱為輕量程序(lightweight processes );是作業系統進行任務排程的基本單元。它與父程序的其它執行緒共享該程序所擁有的全部程式碼 空間和全域性變數,但擁有獨立的堆疊(即區域性變數對於執行緒來說是私有的)。

1.1 執行緒和程序的區別:

  1. 執行緒是程序的一部分,所以執行緒有的時候被稱為是輕量級程序。
  2. 一個沒有執行緒的程序是可以被看作單執行緒的,如果一個程序內擁有多個執行緒, 程序的執行過程不是一條線(執行緒)的,而是多條線(執行緒)共同完成的。
  3. 系統在執行的時候會為每個程序分配不同的記憶體區域,但是不會為執行緒分配記憶體(執行緒所使 用的資源是它所屬的程序的資源),執行緒組只能共享資源。那就是說,除了CPU之外(執行緒在運 行的時候要佔用CPU資源),計算機內部的軟硬體資源的分配與執行緒無關,執行緒只能共享它所屬 程序的資源。
  4. 與程序的控制表PCB相似,執行緒也有自己的控制表TCB,但是TCB中所儲存的執行緒狀態比PCB表 中少很多
  5. 程序是系統所有資源分配時候的一個基本單位,擁有一個完整的虛擬空間地址,並不依賴線 程而獨立存在。

更加詳細的介紹,請參考這裡

1.2 執行緒的優點

由於以下原因,行業內廣泛地在程式設計庫和作業系統中實現執行緒:

  • 減少記憶體佔用量。建立另一個執行緒的記憶體消耗量被限制為執行緒所需要的堆疊加上執行緒管理器需 要的一些簿記記憶體。
  • 不需要採用先進的技術來訪問伺服器全域性資料。如果資料有可能由另一個同時執行的執行緒修改, 則要做的一切就是使用互斥體 保護相關段。
  • 建立執行緒所需要的時間大大小於建立程序所需要的時間,原因是不必複製堆部分(它可能很大)。
  • 線上程之間進行環境切換時,核心在排程器中花的時間比在過程之間進行切換花的時間少。 這給負擔很重的伺服器留下了更多的cpu時間處理工作。

1.3 執行緒的缺點

儘管執行緒在現代計算機中極具重要性,它們卻有很多缺點:

  • 程式設計錯誤代價慘重。如果一個執行緒崩潰,會使得整個伺服器停止。一個壞執行緒可能會毀壞全域性 資料,導致其他執行緒無法工作
  • 容易產生程式設計錯誤。程式設計師必須不斷考慮其他一些執行緒可能正在做引起麻煩的事情,以及如何 避免這種麻煩。需要採用額外的防範方法編制程式。
  • 執行緒伺服器在同步漏洞方面聲名狼藉,這些漏洞幾乎無法在測試中進行復制,卻在生產期間很 不合時宜地出現。這類漏洞發生機率之所以如此高,是由於使用共享地址空間,這會產生更高程 度的執行緒互動。
  • 有時候互斥體爭用難以控制。如果在同一時間有太多的執行緒想得到相同的互斥體,就會導致過 度的環境切換,大量的CPU時間就會花在核心排程器上,因而幾乎沒有時間執行工作。
  • 32位系統限制為每個執行緒使用4G地址空間。由於所有的執行緒都共享相同的地址空間,理論上整 個伺服器就被限制為使用4G RAM,即便實際上有更多的物理RAM也不例外。實際使用時,地址空間 會在一個小得多的限值下開始變得非常擁擠。
  • 擁擠的32位地址空間會帶來另一個問題。每個執行緒都需要一些堆疊空間,在分配了堆疊後, 即便不使用所分配的大部分空間,伺服器也會為其保留地址空間。每個新堆疊都會減少用於堆的 潛在空間。因此,即使有足夠的實體記憶體,也不可能同時使用大型緩衝區,同時使用大量併發線 程,以及同時為每個執行緒提供足夠的堆疊空間。

1.4 程序的優點

執行緒的缺點與使用多程序的優點相對應:

  • 程式設計錯誤並不致命。儘管有可能發生,但一個壞分支伺服器程序並不容易中斷整個伺服器。
  • 程式設計錯誤發生的可能性小得多。在大多數時候,程式設計師只需要考慮一個執行緒的執行,而不用受 可能的併發侵入者的打擾。
  • 飄忽不定的漏洞少得多。如果漏洞出現一次,通常非常容易複製。由於各個分支程序有自己的 地址空間,它們之間並沒有太多的互動。
  • 在32位系統中,地址空間用完的問題並不嚴重。

1.5 程序的缺點

  • 記憶體利用不夠好。當子程序發生分支時,會不必要地複製大型記憶體程式段。
  • 需要採用特殊技術實現程序資料共享。(IPC)
  • 建立程序比建立執行緒需要更多的核心系統開銷。對效能的一個很大的打擊是需要 複製父程序的 資料段。不過,Linux 在這方面的手段是執行所謂的copy-on-write 。除非子程序或父程序修改了 父程序頁,否則並不真正複製父程序頁。在此之前,父子程序使用相同的頁。
  • 程序之間的環境切換比執行緒之間的環境切換更為耗時,因為核心需要切換頁,檔案描述符表 及其他額外的內容資訊。留給伺服器執行實際工作的時間減少。

2. 執行緒API

程序原語和執行緒原語的比較:

程序原語 執行緒原語 描述
fork pthread_create 建立新的控制流
exit pthread_exit 從現有的控制流退出
waitpid pthread_join 從控制流中得到退出狀態
atexit pthread_cancle_push 註冊在退出控制流時呼叫的函式
getpid pthread_self 獲取控制流的ID
abort pthread_cancle 請求控制流的非正常退出

3. 讀者-寫者問題

讀者————寫者問題是一個用訊號量實現的經典程序同步問題。在系統中,一個數據集(如檔案或 記錄) 被幾個併發程序共享,這些執行緒分兩類,一部分只要求進行讀操作,稱之為“讀者”; 另一類要求寫或修改操作,我們稱之為“寫者“。一般而言,對一個數據集,為了保證資料的完整 性、正確性,允許多個讀者程序同時訪問,但是不允許一個寫者程序同其它任何一個程序(讀者 或者寫者)同時訪問,而這類問題就稱之為"讀者-寫者"問題。

讀者優先的演算法在作業系統相關的書籍中都有介紹,這是一種最簡單的解決辦法: 當沒有寫進 程正在訪問共享資料集時,讀程序可以進入訪問,否則必須等待。而讀者優先的演算法存在"餓死 寫者"執行緒的問題:只要有讀者不斷到來,寫者就要持久地等待,直到所有的讀者都讀完且沒有 新的讀者到來時寫者才能寫資料集。而在很多情況下我們需要避免"餓死寫者",故而採用寫者優 先演算法:

在寫者優先演算法中,我們要實現的目標是:

1.要讓讀者與寫者之間、以及寫者與寫者之問要互斥地訪同資料集; 2.在無寫程序到來時各讀者可同時訪問資料集; 3.在讀者和寫者都等待時訪問時寫者優先.

在實現寫者優先時,增加一個互斥量,用於寫者優先。當有寫者來時,就不在允許讀者去讀取資料, 等待正在讀資料的讀者完成以後開始寫資料,以此實現寫者優先。

4. 哲學家就餐問題

哲學家就餐問題可以這樣表述,假設有五位哲學家圍坐在一張圓形餐桌旁,做以下兩件事 情之一:吃飯,或者思考。吃東西的時候,他們就停止思考,思考的時候也停止吃東西。餐桌中 間有一大碗義大利麵,每兩個哲學家之間有一隻餐叉。因為用一隻餐叉很難吃到義大利麵,所以 假設哲學家必須用兩隻餐叉吃東西。他們只能使用自己左右手邊的那兩隻餐叉。哲學家就餐問題 有時也用米飯和筷子而不是義大利麵和餐叉來描述,因為很明顯,吃米飯必須用兩根筷子。

多執行緒程式設計示例

5 互斥量(mutex)

互斥鎖建立

有兩種方法建立互斥鎖,靜態方式和動態方式。POSIX定義了一個巨集PTHREAD_MUTEX_INITIALIZER 來靜態初始化互斥鎖,方法如下:

  1. pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;在LinuxThreads實現中, pthread_mutex_t是一個結構,而PTHREAD_MUTEX_INITIALIZER則是一個結構常量。

  2. 動態方式是採用pthread_mutex_init()函式來初始化互斥鎖,API定義如下:

    int pthread_mutex_init(pthread_mutex_t*mutex,constpthread_mutexattr_t*mutexattr)

    其中mutexattr用於指定互斥鎖屬性(見下),如果為NULL則使用預設屬性。 pthread_mutex_destroy ()用於登出一個互斥鎖,API定義如下:

    int pthread_mutex_destroy(pthread_mutex_t*mutex)

鎖操作

鎖操作主要包括加鎖pthread_mutex_lock()、解鎖pthread_mutex_unlock()和測試加鎖 pthread_mutex_trylock()三個,不論哪種型別的鎖,都不可能被兩個不同的執行緒同時得到, 而必須等待解鎖。對於普通鎖和適應鎖型別,解鎖者可以是同進程內任何執行緒; 而檢錯鎖則必須由加鎖者解鎖才有效,否則返回EPERM;對於巢狀鎖,文件和實現要求必須由 加鎖者解鎖,但實驗結果表明並沒有這種限制,這個不同目前還沒有得到解釋。在同一程序中 的執行緒,如果加鎖後沒有解鎖,則任何其他執行緒都無法再獲得鎖。

int pthread_mutex_lock(pthread_mutex_t*mutex)int pthread_mutex_unlock(pthread_mutex_t*mutex)int pthread_mutex_trylock(pthread_mutex_t*mutex)

pthread_mutex_trylock() 語義與pthread_mutex_lock()類似,不同的是在鎖已經被佔據時返回 EBUSY而不是掛起等待。

互斥量實現讀者寫者問題

#include<pthread.h>#include<signal.h>#include"apue.h"#define N 5//No. of reader#define M 5//No. of reading and writingpthread_mutex_t rd = PTHREAD_MUTEX_INITIALIZER;// it's mean reader can readingpthread_mutex_t wr = PTHREAD_MUTEX_INITIALIZER;//it's mean writer can writingint readCount =0;void* reader(void*arg){int n = M;int id =(int)arg;while(n--){
        sleep( rand()%3);
        pthread_mutex_lock(&rd);
        readCount++;if( readCount ==1){
            pthread_mutex_lock(&wr);}
        pthread_mutex_unlock(&rd);

        printf("reader %d is reading\n", id);
        sleep( rand()%3);

        pthread_mutex_lock(&rd);
        readCount--;if(readCount ==0){
            pthread_mutex_unlock(&wr);}
        pthread_mutex_unlock(&rd);
        printf("reader %d is leaving\n", id);}
    printf("----reader %d has done----\n",(int)arg);}void* writer(void*arg){int n = M;while(n--){
        sleep( rand()%3);
        pthread_mutex_lock(&wr);
        printf("\twriter is writing\n");
        sleep( rand()%3);
        pthread_mutex_unlock(&wr);
        printf("\twriter is leaving\n");}
    printf("----writer has done----\n");}int main(int argc,constchar*argv[]){int err;pthread_t tid[N], writerTid;int i;


    err = pthread_create(&writerTid, NULL, writer,(void*)NULL);if(err !=0){
        err_quit("can't create process for writer");}for(i =0; i < N; i++){
        err = pthread_create(&tid
            
           

相關推薦

linux多種比較

最近研究MySQL原始碼,各種鎖,各種互斥,好在我去年認真學了《unix環境高階程式設計》, 雖然已經忘得差不多了,但是學過始終是學過,拿起來也快。寫這篇文章的目的就是總結Linux 下多執行緒程式設計,作為日後的參考資料。 本文將介紹linux系統下多執行緒程式設計中,執行緒同步的各種方法。包

linux互斥實現的簡單的生產者消費者問題

這個程式實現的功能很簡單,也算是入門linux下的多執行緒程式設計了吧~ 其創造了兩個生產者和一個消費者,兩個生產者通過互斥鎖實現同步,往緩衝區裡放入資料,資料的值和其下標值一樣,方便消費者的檢驗 消費者等到生產者放完資料後,從緩衝區中取出資料,並進行檢驗,看是否有出現差錯,沒有的話

linux互斥的使用

原始碼如下 #include <cstdio> #include <cstdlib> #include <unistd.h> #include "iostream" #include <pthread.h>

Linuxcomm命令比較兩個文件的異同

系統 遵從 我們 註意 所有 幫助 說明 div 版本 在操作文件的時候我們可能需要找到兩個文件的交集、並集或補集,Linux系統下可以用一個簡單的命令實現--comm命令,不同於diff命令,它不需要事先排好序,也不是一行一行的比較差異,下面是幫助文檔說明 用法:c

linuxselect/poll/epoll機制的比較

解決方案 socket 下一步 linux 操作系統 select、poll、epoll簡介epoll跟select都能提供多路I/O復用的解決方案。在現在的Linux內核裏有都能夠支持,其中epoll是Linux所特有,而select則應該是POSIX所規定,一般操作系統均有實現sele

Linux 常見的四款chm查看器比較[轉載+親測可用]

源代碼 libraries ref qlite 處理 del 開源軟件 linux系統 usr 在linux系統下閱讀chm格式的電子書,著實要費一番周折。本文旨在介紹幾款linu系統下的chm查看器,方便讀者閱讀。 一、CHMSEE ChmSee 由國人開發,程序

linux字符串的比較方式

ont cells $1 div 匹配 .sh func contain clas A="$1" B="$2" #判斷字符串是否相等 if [ "$A" = "$B" ];then echo "[ = ]" fi #判斷字符串是否相等,與上面的=

Linuxping,telnet,ssh命令的比較

spa login works form 不同 是否 檢測 issues 其他 ping工作在OSI模型的第三層,網絡層。 主要用於測試到達目的主機的網絡是否連接,不能檢測某個端口是否開放。 ping使用ICMP協議,不使用某個特定端口。 也可以 ping 域名 ,這樣可以

linux用互斥和條件變數來實現讀寫

以下內容來源自UNP卷二的第八章 讀寫鎖的概念( the conception of read-write lock ) (1)只要沒有執行緒持有某個給定的讀寫鎖用於寫,那麼任意數目的執行緒可以持有該執行緒用於讀 (2)僅當沒有執行緒持有某個給定的讀寫鎖用於讀或用於寫,才能分配該

Linux產生隨機數碼的多種方法

文章目錄 第一種:藉助環境變數$RANDOM 1. 產生0-25範圍內的數,用這個環境變數對26取餘即可。 2. 產生6位數的整數,用這個環境變數加上100000即可。

Linux的二進位制檔案比較工具

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

linux檔案比較工具diff|cmp使用小結

轉自:http://blog.csdn.net/wangjianno2/article/details/50451737,記錄下便於忘記時查詢。 1.diff diff是Unix系統的一個很重要的工具程式。它用來比較兩個文字檔案的差異,是程式碼版本管理的基石之一。 2.diff使用

不區分大小寫的串比較---Windows的stricmp和Linux的strcasecmp

 不區分大小寫的串比較, 在實戰中的應用還是很廣泛的, 有時候可以增強程式的容錯性, 下面我們來分別看看Windows下的stricmp和Linux下的strcasecmp       Windows下的stricmp: #in

Linux程式設計用到的

執行緒之間的鎖有:互斥鎖、條件鎖、自旋鎖、讀寫鎖、遞迴鎖。一般而言,鎖的功能越強大,效能就會越低。 1、互斥鎖 互斥鎖用於控制多個執行緒對他們之間共享資源互斥訪問的一個訊號量。也就是說是為了避免多個執行緒在某一時刻同時操作一個共享資源。例如執行緒池中的有多個空閒執行緒和一個任務佇列。

linux核心態與使用者態詳細介紹

1 核心態下鎖 spinlock_t成為自旋鎖,它用在臨界區程式碼非常少的情況下。自旋鎖不會引起呼叫者睡眠,如果自旋鎖已經被別的執行單元保持,呼叫者就一直迴圈在那裡看是否該自旋鎖的保持者已經釋放了鎖,如果釋放了該鎖,請求鎖的呼叫者可以立即得到它,繼續執行。自旋鎖可用於中

Linux使用者與解問題

一:登入失敗次回超過限制1)鎖使用者的設定 /etc/pam.d/下包含各種認證程式或服務的配置檔案。編輯這些可限制認證失敗次數,當失敗次數超過指定值時使用者會被鎖住。 在此,以run level為3的時候,多次登入登入失敗即鎖使用者為例: 在/etc/pam.d/login檔案中追加如下兩行:auth re

Linuxyum命令被

       最近做一個電商的專案,需要在Linux系統環境下安裝搭建nginx。如我們所知,安裝nginx之前需要安裝它需要的環境,安裝這些環境用到yum命令。        yum即 Yellow

linux的檔案壓縮方式比較

        本文主要討論linux下常見的各種檔案解壓縮方式,同時比較各類壓縮方式的壓縮率和壓縮時間。         一、我們來說說常見的壓縮檔案格式:    

Linux檔案輕鬆比對,自由開源的比較軟體

from : http://www.linuxidc.com/Linux/2015-01/111973.htm Meld Meld是一個適用於Gnome桌面的、開源的、圖形化的檔案差異檢視和合並的應用程式。它支援2到3個檔案的同時比較、遞迴式的目錄比較、處於版

linux使用gdb除錯崩潰丶死例項

gdb是linux下一款功能強大的除錯工具,windows下對應的有windbg,下面舉例說明常見程式錯誤解決方法 1.gdb啟動 要想使用gdb除錯,編譯時指定-g選項加入除錯資訊,gdb可以啟動執