c-線程創建,同步互斥,互斥鎖;

文章目錄

  • 案例描述1
    • 代碼實現
    • 代碼解釋
  • 案例背景2
    • 代碼實現
    • 代碼解析
    • 關鍵概念總結
    • 擴展練習

案例描述1

我們將模擬一個簡單的售票系統,其中有兩個售票窗口同時出售100張票。為了確保不會賣出超過100張票,并且不會出現賣票時的競態條件(race condition),我們將使用互斥鎖來保護共享資源——剩余票數。

代碼實現

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>#define NUM_TICKETS 100
#define NUM_THREADS 2int tickets = NUM_TICKETS;
pthread_mutex_t mutex;void* sell_tickets(void* arg) {while (1) {pthread_mutex_lock(&mutex); // 獲取互斥鎖if (tickets > 0) {printf("Thread %ld sold ticket: %d\n", (long)arg, tickets);tickets--;pthread_mutex_unlock(&mutex); // 釋放互斥鎖} else {pthread_mutex_unlock(&mutex); // 釋放互斥鎖break; // 如果沒有票了,退出循環}// 模擬線程間的切換,增加并發沖突的可能性// 可以通過注釋掉下面這行代碼來查看效果usleep(100); // 線程休眠100微秒}return NULL;
}int main() {pthread_t threads[NUM_THREADS];// 初始化互斥鎖if (pthread_mutex_init(&mutex, NULL) != 0) {printf("Mutex init failed\n");return -1;}// 創建兩個線程for (int i = 0; i < NUM_THREADS; i++) {if (pthread_create(&threads[i], NULL, sell_tickets, (void*)(intptr_t)(i + 1)) != 0) {printf("Thread creation failed\n");return -1;}}// 等待所有線程完成for (int i = 0; i < NUM_THREADS; i++) {pthread_join(threads[i], NULL);}// 銷毀互斥鎖pthread_mutex_destroy(&mutex);printf("All tickets have been sold.\n");return 0;
}

代碼解釋

  • pthread_mutex_t mutex;:定義了一個互斥鎖變量。
  • pthread_mutex_lock(&mutex);pthread_mutex_unlock(&mutex);:分別用于獲取和釋放互斥鎖。當一個線程獲取到互斥鎖后,其他試圖獲取同一互斥鎖的線程將被阻塞,直到第一個線程釋放該鎖。
  • usleep(100);:讓當前線程暫停一段時間,模擬線程間的時間片輪轉,以便觀察到并發沖突的情況。如果注釋掉這一行,可能會減少并發沖突的機會,因為線程可能在執行完一次賣票操作前不會被打斷。
  • pthread_create(&threads[i], NULL, sell_tickets, (void*)(intptr_t)(i + 1));:創建新線程并開始執行sell_tickets函數。

通過這個例子,您可以清楚地看到如何在線程之間安全地共享資源以及如何避免競態條件。請注意,在實際應用中,需要根據具體情況調整互斥鎖的應用范圍,以最小化鎖的粒度,從而提高程序的效率。
好的!我將通過一個詳細的嵌入式案例,幫助你理解 線程創建、同步互斥和互斥鎖 的概念。我們將使用 POSIX 線程(pthread)庫 在 Linux 環境下實現,這是嵌入式開發中常用的多線程編程方法。


案例背景2

假設我們有一個嵌入式系統,需要同時采集傳感器數據(如溫度)和進行數據處理。為了避免數據競爭,我們需要:

  1. 創建兩個線程:一個負責采集數據,另一個負責處理數據。
  2. 使用 互斥鎖(Mutex) 保護共享數據(傳感器數據)。

代碼實現

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>  // 用于 sleep 函數// 定義共享數據
int sensor_data = 0;// 定義互斥鎖
pthread_mutex_t mutex;// 線程1:采集傳感器數據
void *sensor_thread(void *arg) {while (1) {pthread_mutex_lock(&mutex);  // 加鎖sensor_data++;               // 修改共享數據printf("Sensor采集數據: %d\n", sensor_data);pthread_mutex_unlock(&mutex);  // 解鎖sleep(1);  // 模擬采集耗時}return NULL;
}// 線程2:處理傳感器數據
void *process_thread(void *arg) {while (1) {pthread_mutex_lock(&mutex);  // 加鎖int data = sensor_data;     // 讀取共享數據printf("Process處理數據: %d\n", data);pthread_mutex_unlock(&mutex);  // 解鎖sleep(2);  // 模擬處理耗時}return NULL;
}int main() {pthread_t tid1, tid2;// 初始化互斥鎖pthread_mutex_init(&mutex, NULL);// 創建兩個線程pthread_create(&tid1, NULL, sensor_thread, NULL);pthread_create(&tid2, NULL, process_thread, NULL);// 等待線程結束(實際中可能需要信號量控制)pthread_join(tid1, NULL);pthread_join(tid2, NULL);// 銷毀互斥鎖pthread_mutex_destroy(&mutex);return 0;
}

代碼解析

  1. 共享數據與互斥鎖

    • sensor_data 是共享的全局變量,會被兩個線程同時訪問。
    • pthread_mutex_t mutex 定義了一個互斥鎖,用于保護對 sensor_data 的訪問。
  2. 線程函數

    • sensor_thread:模擬傳感器數據采集,每次對 sensor_data 加1。
    • process_thread:模擬數據處理,讀取 sensor_data 的值。
    • 在訪問共享數據前,通過 pthread_mutex_lock 加鎖;操作完成后,通過 pthread_mutex_unlock 解鎖。
  3. 主函數

    • 初始化互斥鎖 pthread_mutex_init
    • 創建兩個線程 pthread_create
    • 等待線程結束 pthread_join(實際項目中可能需要更復雜的同步機制)。

關鍵概念總結

  1. 互斥鎖(Mutex)

    • 用于保護共享資源,確保同一時間只有一個線程訪問。
    • 操作:lock(加鎖) → 臨界區操作 → unlock(解鎖)。
  2. 線程同步

    • 通過互斥鎖協調多個線程的執行順序,避免數據競爭(Data Race)。
  3. 嵌入式場景注意事項

    • 避免死鎖:確保加鎖后一定會解鎖。
    • 最小化臨界區:減少鎖的持有時間,提高系統實時性。

擴展練習

  1. 嘗試移除互斥鎖,觀察數據不一致的現象。
  2. 添加第三個線程(如數據上傳線程),進一步練習多線程同步。
  3. 研究其他同步機制(如信號量、條件變量)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/73232.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/73232.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/73232.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringBoot第二天

目錄 1.Web開發 1.1簡介 1.2SpringBoot對靜態資源的映射規則 1.3模板引擎 1.3.1引入thymeleaf&#xff1b; 1.3.2Thymeleaf語法 1.3.2.1標準表達式語法 1.變量表達式 1.3.2.2表達式支持的語法 1.3.2.3常用的thymeleaf標簽 1.4Springboot整合springmvc 1.4.1Springmvc…

Redis的緩存雪崩、緩存擊穿、緩存穿透與緩存預熱、緩存降級

一、緩存雪崩&#xff1a; 1、什么是緩存雪崩&#xff1a; 如果緩在某一個時刻出現大規模的key失效&#xff0c;那么就會導致大量的請求打在了數據庫上面&#xff0c;導致數據庫壓力巨大&#xff0c;如果在高并發的情況下&#xff0c;可能瞬間就會導致數據庫宕機。這時候如果…

Html5記憶翻牌游戲開發經驗分享

H5記憶翻牌游戲開發經驗分享 這里寫目錄標題 H5記憶翻牌游戲開發經驗分享前言項目概述技術要點解析1. 頁面布局&#xff08;HTML CSS&#xff09;響應式設計 2. 翻牌動畫效果3. 游戲邏輯實現狀態管理卡片配對檢測 開發技巧總結1. 模塊化設計2. 性能優化3. 用戶體驗 踩坑經驗擴…

【開源+代碼解讀】Search-R1:基于強化學習的檢索增強大語言模型框架3小時即可打造個人AI-search

大語言模型(LLMs)在處理復雜推理和實時信息檢索時面臨兩大挑戰:知識局限性(無法獲取最新外部知識)和檢索靈活性不足(傳統方法依賴固定檢索流程)。現有方法如檢索增強生成(RAG)和工具調用(Tool-Use)存在以下問題: RAG:單輪檢索導致上下文不足,無法適應多輪交互場景…

Linux網絡套接字編程——創建并綁定

目錄 網絡字節序 socket編程接口 socket bind 如果將進程比作一個房子&#xff0c;那套接字相當于是一扇門&#xff0c;通向與外界通信的通道。 在網絡中&#xff0c;如何理解套接字呢&#xff0c;時刻記住套接字是為了標識互聯網中的某一臺主機上的某一個進程&#xff0c…

1720. 解碼異或后的數組

解碼異或后的數組 題目描述嘗試做法 題目描述 未知整數數組 arr 由 n 個非負整數組成。 經編碼后變為長度為 n - 1 的另一個整數數組 encoded &#xff0c;其中 encoded[i] arr[i] XOR arr[i 1] 。例如&#xff0c;arr [1,0,2,1] 經編碼后得到 encoded [1,2,3] 。 給你編…

了解一下HTTP的短連接和長連接

在 HTTP 協議中&#xff0c;連接的方式主要分為長連接和短連接。這兩種連接方式的主要區別在于連接的生命周期和數據傳輸的效率。理解它們的差異對于優化 Web 應用的性能和資源利用至關重要。以下是 HTTP 長連接和短連接的詳細解釋。 1. 短連接&#xff08;HTTP/1.0&#xff0…

【WRF模擬】如何查看 WPS 的輸入靜態地理數據(二進制格式)?

查看 WPS 的輸入靜態地理數據方法總結 方法 1:使用 gdal_translate 將二進制數據轉換為 GeoTIFFgdal_translate 工具概述使用 gdal_translate 將二進制數據轉換為 GeoTIFF方法 2:使用 ncdump 查看 geo_em.dXX.nc方法 3:使用 Python xarray + matplotlib 可視化 geo_em.dXX.n…

Mybatis語法bug

select * from appointment where status ‘ACCEPTED’ and expire_time< now() idea顯示now&#xff08;&#xff09;這里一直報錯&#xff1a; 應為標記名稱 應為 Deepseek: 根據您的代碼和報錯信息分析&#xff0c;這是一個 MyBatis XML 文件中的 SQL 語法問題。具體原…

DeepSeek本機部署(基于Ollama和Docker管理)

目錄 一、ollama 與 docker 簡介 &#xff08;一&#xff09;ollama(Ollama) &#xff08;二&#xff09;docker 二、利用 ollama 和 docker 配置 deepseek-r1 的準備工作 &#xff08;一&#xff09;硬件需求 &#xff08;二&#xff09;軟件安裝 三、配置 deepseek-r1…

小程序 wxml 語法 —— 39 簡單雙向數據綁定

在 WXML 中&#xff0c;普通屬性的綁定是單向的&#xff0c;比如 <input value"{{ value }}" />&#xff0c;當數據發生改變時&#xff0c;頁面也會隨之發生變化&#xff0c;但是當用戶在輸入框中輸入最新內容&#xff0c;最新內容并不會同步給 value 數據&…

Linux第一次練習

1、找到你的Linux系統上的不同顏色的文件&#xff0c;每一種顏色的文件找到3個以上 藍色&#xff1a; 白色&#xff1a; 綠色&#xff1a; 紅色&#xff1a; 黃色&#xff1a; 2、設置一個ping的別名永久生效&#xff0c;設置一個ymd的別名date %F永久生效

《C#上位機開發從門外到門內》2-2:I2C總線協議及其應用詳解

文章目錄 一、引言二、I2C總線協議的基本概念三、I2C通信機制3.1 硬件結構與基本原理3.2 信號的起始與終止3.3 數據傳輸格式及時序3.4 時鐘同步與時鐘伸展 四、設備尋址與數據傳輸4.1 I2C設備尋址方式4.2 地址沖突及解決方法4.3 數據傳輸過程中的確認機制4.4 I2C數據幀結構與傳…

Trae IDE:解鎖 AI 驅動的高效編程體驗

Trae 介紹 Trae 是字節跳動推出的一款面向開發者的 AI 驅動的集成開發環境&#xff08;IDE&#xff09;&#xff0c;于 2024 年 1 月 19 日在新加坡正式發布海外版&#xff0c;2025 年 3 月 3 日發布國內版。海外版由字節跳動旗下的 SPRING&#xff08;SG&#xff09;PTE.LTD.…

玩轉python:通俗易懂掌握高級數據結構:collections模塊之namedtuple

引言 namedtuple是Python中collections模塊提供的一個強大工具&#xff0c;用于創建具有字段名的元組。它不僅具備元組的不可變性&#xff0c;還能通過字段名訪問元素&#xff0c;極大地提高了代碼的可讀性和可維護性。本文將詳細介紹namedtuple的關鍵用法和特性&#xff0c;并…

我的創作紀念日:730天的技術寫作之旅

我的創作紀念日&#xff1a;730天的技術寫作之旅 機緣 從一篇案例分析開始 2023年3月13日&#xff0c;我寫下了第一篇技術博客《軟考高級-系統分析師-案例分析-系統維護與設計模式》。那時的初心很簡單&#xff1a; 沉淀實戰經驗——在備考軟考系統分析師時&#xff0c;發現…

使用 Arduino 和 ESP8266 Wi-Fi 模塊發送電子郵件

使用 Arduino Uno 和 ESP8266 Wi-Fi 模塊發送電子郵件 我們正在邁向物聯網 (IoT) 世界。這項技術在電子和嵌入式系統中起著非常重要的作用。從任何微控制器或嵌入式系統發送電子郵件都是非常基本的事情,這在 IoT 中是必需的。因此,在本文中,我們將學習“如何使用 Wi-Fi 和…

golang算法二叉樹對稱平衡右視圖

100. 相同的樹 給你兩棵二叉樹的根節點 p 和 q &#xff0c;編寫一個函數來檢驗這兩棵樹是否相同。 如果兩個樹在結構上相同&#xff0c;并且節點具有相同的值&#xff0c;則認為它們是相同的。 示例 1&#xff1a; 輸入&#xff1a;p [1,2,3], q [1,2,3] 輸出&#xff1a…

c++介紹智能指針 十二(1)

普通指針&#xff1a;指向內存區域的地址變量。使用普通指針容易出現一些程序錯誤。 如果一個指針所指向的內存區域是動態分配的&#xff0c;那么這個指針變量離開了所在的作用域&#xff0c;這塊內存也不會自動銷毀。動態內存不進行釋放就會導致內存泄露。如果一個指針指向已…

亞馬遜COSMO算法解讀:新搜索時代的流量分配與DeepBI AI驅動的智能優化策略

亞馬遜COSMO算法的推出&#xff0c;標志著其搜索和推薦系統進入了智能化、個性化的新階段。該算法通過分析用戶購物習慣、搜索歷史、瀏覽行為等數據&#xff0c;為買家提供精準推薦&#xff0c;同時對賣家的運營策略提出了更高的要求。在這一背景下&#xff0c;AI驅動的DeepBI能…