linux線程同步(1)-互斥量

来源:http://www.cnblogs.com/yuuyuu/archive/2016/01/18/5140251.html
-Advertisement-
Play Games

一.概述 互斥量是線程同步的一種機制,用來保護多線程的共用資源。同一時刻,只允許一個線程對臨界區進行訪問。互斥量的工作流程:創建一個互斥量,把這個互斥量的加鎖調用放在臨界區的開始位置,解鎖調用放到臨界區的結束位置。當內核優先把某個線程調度到臨界區的開始...


一.概述                                                  

互斥量是線程同步的一種機制,用來保護多線程的共用資源。同一時刻,只允許一個線程對臨界區進行訪問。

互斥量的工作流程:創建一個互斥量,把這個互斥量的加鎖調用放在臨界區的開始位置,解鎖調用放到臨界區的結束位置。當內核優先把某個線程調度到臨界區的開始位置時,線程執行這個加鎖調用,併進入臨界區對資源進行操作。此時其他線程再被內核調度到這裡的時候,由於該互斥量已被加鎖狀態,得不到鎖會一直阻塞在這裡,導致其他線程不能進入臨界區,直到剛剛那個進入臨界區的線程離開臨界區並執行解鎖調用。

二.函數介面                                           

1.初始化互斥量

互斥量是一個pthread_mutex_t類型的變數。

1.1:用巨集常量初始化:

1 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

1.2:用函數初始化:

1 #include <pthread.h>
2 
3 int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);

mutex:互斥量結構指針

attr:互斥量的屬性結構指針

2.設置互斥量屬性

1 #include <pthread.h>
2 
3 int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);

attr:互斥量的屬性結構指針

type:PTHREAD_MUTEX_NORMAL(預設屬性),PTHREAD_MUTEX_ERRORCHECK(會進行錯誤檢查,速度比較慢),PTHREAD_MUTEX_RECURSIVE(遞歸鎖)。對於遞歸鎖,同一個線程對一個遞歸鎖加鎖多次,會有一個鎖計數器,解鎖的時候也需要解鎖這個次數才能釋放該互斥量。

3.加鎖與解鎖

1 #include <pthread.h>
2 
3 int pthread_mutex_lock(pthread_mutex_t *mutex);
4 int pthread_mutex_trylock(pthread_mutex_t *mutex);
5 int pthread_mutex_unlock(pthread_mutex_t *mutex);

參數都是互斥量指針。pthread_mutex_lock()得不到鎖會阻塞,int pthread_mutex_trylock()得不到鎖會立即返回,並返回EBUSY錯誤。

還有一個pthread_mutex_timedlock()會根據時間來等待加鎖,如果這段時間得不到鎖會返回ETIMEDOUT錯誤!

1 #include <pthread.h>
2 #include <time.h>
3 
4 int pthread_mutex_timedlock(pthread_mutex_t *restrict mutex, const struct timespec *restrict abs_timeout);

4.銷毀互斥量

1 #include <pthread.h>
2 
3 int pthread_mutex_destroy(pthread_mutex_t *mutex);

mutex:創建的互斥量指針

三.簡單例子                                            

寫個簡單的例子,主線程消費,子線程生產,並模擬使用過程中可能遇到的缺點

 1 /**
 2  * @file pthread_mutex.c
 3  */
 4 
 5 #include <stdio.h>
 6 #include <stdlib.h>
 7 #include <string.h>
 8 #include <unistd.h>
 9 #include <pthread.h>
10 
11 /* 定義互斥量 */
12 pthread_mutex_t mtx;
13 /* 互斥量屬性 */
14 pthread_mutexattr_t mtx_attr;
15 /* 全局資源 */
16 int money;
17 
18 void err_exit(const char *err_msg)
19 {
20     printf("error:%s\n", err_msg);
21     exit(1);
22 }
23 
24 /* 線程函數 */
25 void *thread_fun(void *arg)
26 {
27     while (1)
28     {
29         /* 加鎖 */
30         pthread_mutex_lock(&mtx);
31 
32         printf("子線程進入臨界區查看money\n");
33         if (money == 0)
34         {
35             money += 200;
36             printf("子線程:money = %d\n", money);
37         }
38 
39         /* 解鎖 */
40         pthread_mutex_unlock(&mtx);
41 
42         sleep(1);
43     }
44 
45     return NULL;
46 }
47 
48 int main(void)
49 {
50     pthread_t tid;
51 
52     /* 初始化互斥量屬性 */
53     if (pthread_mutexattr_init(&mtx_attr) == -1)
54         err_exit("pthread_mutexattr_init()");
55 
56     /* 設置互斥量屬性 */
57     if (pthread_mutexattr_settype(&mtx_attr, PTHREAD_MUTEX_NORMAL) == -1)
58         err_exit("pthread_mutexattr_settype()");
59 
60     /* 初始化互斥量 */
61     if (pthread_mutex_init(&mtx, &mtx_attr) == -1)
62         err_exit("pthread_mutex_init()");
63 
64     /* 創建一個線程 */
65     if (pthread_create(&tid, NULL, thread_fun, NULL)== -1)
66         err_exit("pthread_create()");
67 
68     money = 1000;
69     while (1)
70     {
71         /* 加鎖 */
72         pthread_mutex_lock(&mtx);
73 
74         if (money > 0)
75         {
76             money -= 100;
77             printf("主線程:money = %d\n", money);
78         }
79 
80         /* 解鎖 */
81         pthread_mutex_unlock(&mtx);
82 
83         sleep(1);
84     }
85 
86     return 0;
87 }

主線程和子線程都對money的操作進行了互斥量保護。68行,初始化money是1000,主線程每次消耗100,子線程只有到money是0是才會生產。sleep(1)防止獨占cpu,也方便列印信息。編譯運行:

可以看到這裡有個非常浪費資源的問題:主線程消耗money的時候,子線程它不知道什麼時候才消耗完,每次內核調度到它時,它都進入臨界區加鎖互斥量,然後查看money,再解鎖。這無意義的操作,簡直是極大的浪費!有什麼辦法可以解決這個問題呢?它有一個好伙伴,叫條件變數

四.死鎖                                                  

假設:當線程1獲取鎖1,再獲取鎖2後才能進入臨界區1,線程2獲取鎖2,再獲取鎖1才能進入臨界區2。某個時刻,線程1獲取了鎖1,再去獲取鎖2的時候發現鎖2已經被線程2鎖住了,而線程2獲取鎖2後,發現鎖1被線程1鎖住了。這樣2個線程誰也不讓誰,都進不了自己的臨界區,就產生了死鎖現象!一般遇到這種情況常見的解決辦法是:規定統一的加鎖順序。線程1和線程2都按照先鎖1,再鎖2。還一種就是使用pthread_mutex_trylock(),如果該函數返回EBUSY錯誤,就釋放這個線程的所有鎖,不過效率有點低。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 技術若只如初見,那麼還會踩坑麽? 在系統引入 MongoDB 也有幾年了,一開始是因為 MySQL 中有單表記錄增長太快(每天幾千萬條吧)容易拖慢 MySQL 的主從複製。而這類數據增長迅速的流水錶,對數據一致性也沒那麼高要求,而且業務上也不需要關聯查詢它,就考慮分出去。為什麼是 M...
  • 在MySQL中間件出現之前,對於MySQL主從集群,如果要實現其讀寫分離,一般是在程式端實現,這樣就帶來一個問題,即資料庫和程式的耦合度太高,如果我資料庫的地址發生改變了,那麼我程式端也要進行相應的修改,如果資料庫不小心掛掉了,則同時也意味著程式的不可用,而這對很多應用來說,並不能接受。引入MySQ...
  • Linq分頁的方法用到Skip(),Take()。然而,用SQL腳本進行分頁如何寫呢?首先我們可以通過ROW_NUMBER() OVER進行排序並得到一個帶序號的視圖,再通過序號確定要查找的分頁數據例: 1 DECLARE @pageSize INT ; 2 DECLARE @pageIndex I...
  • 本文目錄列表:1、位運算2、設置日曆數據表節假日標誌3、總結語4、參考清單列表位運算SQL Server支持的按位運算符有三個,分別為:按位與(&)、按位或(|)、按位異或(^)。位運算符用於int、smallint或tinyint數據,目前SQL Server能支持的按位運算的最大整數類型為Int...
  • 該文章為原創,日後可能會根據實際開發經驗和網友評論,進行相應地方修改,為獲得最新博客動態,望在轉發博客的時候註明出處。觸發器要實現的功能:(1)獲取對錶Table1數據操作操作類型(insert、delete或update)。(2)將表修改後的數據保存到表Table2(該表結構與Table1表結構類...
  • 一. 將bootloader燒入SD卡 1.格式化SD卡(不掛載): fdisk /dev/sdx -d 刪除 -n 新建分區 -w 保存退出 6~default sdx1 兩種格式化方式: mkfs -t vfat /dev/sdx1 ...
  • 一.概述 上一篇,介紹了互斥量。條件變數與互斥量不同,互斥量是防止多線程同時訪問共用的互斥變數來保護臨界區。條件變數是多線程間可以通過它來告知其他線程某個狀態發生了改變,讓等待在這個條件變數的線程繼續執行。通俗一點來講:設置一個條件變數讓線程1等待在一...
  • 命令簡介: 該命令用於密碼時效管理。它可以修改賬號和密碼的有效期。對於chage命令的描述如下所示: The chage command changes the number of days between password changes and the date of the last pass...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...