linux線程同步(3)-讀寫鎖

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

一.概述 讀寫鎖與互斥量的功能類似,對臨界區的共用資源進行保護!互斥量一次只讓一個線程進入臨界區,讀寫鎖比它有更高的並行性。讀寫鎖有以下特點:1.如果一個線程用讀鎖鎖定了臨界區,那麼其他線程也可以用讀鎖來進入臨界區,這樣就可以多個線程並行操作。但這個時...


一.概述                                                   

讀寫鎖與互斥量的功能類似,對臨界區的共用資源進行保護!互斥量一次只讓一個線程進入臨界區,讀寫鎖比它有更高的並行性。讀寫鎖有以下特點:

1.如果一個線程用讀鎖鎖定了臨界區,那麼其他線程也可以用讀鎖來進入臨界區,這樣就可以多個線程並行操作。但這個時候,如果再進行寫鎖加鎖就會發生阻塞,寫鎖請求阻塞後,後面如果繼續有讀鎖來請求,這些後來的讀鎖都會被阻塞!這樣避免了讀鎖長期占用資源,防止寫鎖饑餓

2.如果一個線程用寫鎖鎖住了臨界區,那麼其他線程不管是讀鎖還是寫鎖都會發生阻塞!

二.函數介面                                           

1.創建讀寫鎖

1.1:巨集常量初始化

1 pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

1.2:函數初始化

1 #include <pthread.h>
2 
3 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);

rwlock:讀寫鎖的pthread_rwlock_t結構指針

attr:讀寫鎖的屬性結構指針。不需要別的屬性預設為NULL。

2.讀寫鎖加鎖與解鎖

1 #include <pthread.h>
2 
3 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
4 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
5 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

rwlock:創建的讀寫鎖指針

3.其他類型的加鎖

1 #include <pthread.h>
2 #include <time.h>
3 
4 
5 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
6 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
7 
8 int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
9 int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);

try類函數加鎖:如果獲取不到鎖,會立即返回錯誤EBUSY

timed類函數加鎖:如果規定的時間內獲取不到鎖,會返回ETIMEDOUT錯誤!

4.銷毀讀寫鎖

1 #include <pthread.h>
2 
3 int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

三.簡單的例子                                        

創建4個線程,2個線程讀鎖,2個線程寫鎖,觀察4個線程進入臨界區的順序

 1 /**
 2  * @file pthread_rwlock.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_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
13 /* 全局資源 */
14 int global_num = 10;
15 
16 void err_exit(const char *err_msg)
17 {
18     printf("error:%s\n", err_msg);
19     exit(1);
20 }
21 
22 /* 讀鎖線程函數 */
23 void *thread_read_lock(void *arg)
24 {
25     char *pthr_name = (char *)arg;
26 
27     while (1)
28     {
29         /* 讀加鎖 */
30         pthread_rwlock_rdlock(&rwlock);
31 
32         printf("線程%s進入臨界區,global_num = %d\n", pthr_name, global_num);
33         sleep(1);
34         printf("線程%s離開臨界區...\n", pthr_name);
35 
36         /* 讀解鎖 */
37         pthread_rwlock_unlock(&rwlock);
38 
39         sleep(1);
40     }
41 
42     return NULL;
43 }
44 
45 /* 寫鎖線程函數 */
46 void *thread_write_lock(void *arg)
47 {
48     char *pthr_name = (char *)arg;
49 
50     while (1)
51     {
52         /* 寫加鎖 */
53         pthread_rwlock_wrlock(&rwlock);
54 
55         /* 寫操作 */
56         global_num++;
57         printf("線程%s進入臨界區,global_num = %d\n", pthr_name, global_num);
58         sleep(1);
59         printf("線程%s離開臨界區...\n", pthr_name);
60 
61         /* 寫解鎖 */
62         pthread_rwlock_unlock(&rwlock);
63 
64         sleep(2);
65     }
66 
67     return NULL;
68 }
69 
70 int main(void)
71 {
72     pthread_t tid_read_1, tid_read_2, tid_write_1, tid_write_2;
73 
74     /* 創建4個線程,2個讀,2個寫 */
75     if (pthread_create(&tid_read_1, NULL, thread_read_lock, "read_1") != 0)
76         err_exit("create tid_read_1");
77 
78     if (pthread_create(&tid_read_2, NULL, thread_read_lock, "read_2") != 0)
79         err_exit("create tid_read_2");
80 
81     if (pthread_create(&tid_write_1, NULL, thread_write_lock, "write_1") != 0)
82         err_exit("create tid_write_1");
83 
84     if (pthread_create(&tid_write_2, NULL, thread_write_lock, "write_2") != 0)
85         err_exit("create tid_write_2");
86 
87     /* 隨便等待一個線程,防止main結束 */
88     if (pthread_join(tid_read_1, NULL) != 0)
89         err_exit("pthread_join()");
90 
91     return 0;
92 }

2個線程函數的臨界區裡面都sleep(1),測試給足夠的時間看其他線程能不能進來。64行,寫鎖函數裡面,sleep(2),因為寫鎖請求會阻塞後面的讀鎖,2個寫鎖一起請求會讓讀鎖饑餓,所以比39行的sleep(1)多一秒!

編譯運行:

可以看到,讀鎖可以一起進入臨界區,而寫鎖在臨界區裡面等1秒都不會有其他線程能進來!!!


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

-Advertisement-
Play Games
更多相關文章
  • 為了加強安全性,MySQL5.7為root用戶隨機生成了一個密碼,在error log中,關於error log的位置,如果安裝的是RPM包,則預設是/var/log/mysqld.log。一般可通過log_error設置mysql> select @@log_error;+------------...
  • oracle的密碼是存在有效期的,有時候會遇到密碼到期需要重設的情況,查看當前密碼有效期的語句:SELECT * FROM dba_profiles s WHERE s.profile='DEFAULT' AND resource_name='PASSWORD_LIFE_TIME';將密碼的時間限制...
  • 本文目錄列表:1、準備測試數據2、向測試數據表添加相關時間粒度欄位列3、基於日月季年統計彙總的演示4、總結語5、參考清單列表準備測試數據為了提供不同時間粒度示例的演示,就需要測試數據。為了演示方便,本文提供一個測試數據表(登錄信息數據表----LoginInfo),以及改變插入測試數據。該測試數據表...
  • 上一篇,我們介紹了Hive的數據多種方式導入,這樣我們的Hive就有了數據來源了,但有時候我們可能需要純粹的導出,或者集群Hive數據的遷移(不同集群,不同版本),我們就可以通過這兩章的知識來實現。   下麵我們開始介紹hive的數據導出,以及集群Hive數據的遷移進行描述。
  • CROSS APPLY的好處是可以像給函數傳參數一樣向括弧里傳篩選條件,實際上MSDN文檔中就是自定義了一個函數,我這裡直接寫了。 這樣一個顯而易見的好處是,可以通過函數封裝具體演算法來減少代碼變化對外部語句的影響。 最大的好處是:它是針對行集的!它針對每一行進行操作!(不負責評論:我覺得恰當使用可以...
  • #include #include unsigned __stdcall _threadfun(void* pParam){ while(TRUE) { printf("hello world"); }}int main(int argc, char* argv[]...
  • 剛裝上linux無法連接WIFI怎麼辦,這麼辦,跟著敲就行了,簡單好理解!
  • 自旋鎖與互斥量功能一樣,唯一一點不同的就是互斥量阻塞後休眠讓出cpu,而自旋鎖阻塞後不會讓出cpu,會一直忙等待,直到得到鎖!!!自旋鎖在用戶態使用的比較少,在內核使用的比較多!自旋鎖的使用場景:鎖的持有時間比較短,或者說小於2次上下文切換的時間。自旋鎖在用戶態的函數介面和互斥量一樣,把pthrea...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...