【linux學習指南】線程同步與互斥

請添加圖片描述

文章目錄

  • 📝線程互斥
  • 🌠 庫函數strncpy
    • 🌉進程線程間的互斥相關背景概念
    • 🌉互斥量mutex
  • 🌠線程同步
    • 🌉條件變量
    • 🌉同步概念與競態條件
    • 🌉 條件變量函數
  • 🚩總結


📝線程互斥

🌠 庫函數strncpy

🌉進程線程間的互斥相關背景概念

  • 臨界資源:多線程執?流共享的資源就叫做臨界資源
  • 臨界區:每個線程內部,訪問臨界資源的代碼,就叫做臨界區
  • 互斥:任何時刻,互斥保證有且只有?個執?流進?臨界區,訪問臨界資源,通常對臨界資源起保護作?
  • 原?性(后?討論如何實現):不會被任何調度機制打斷的操作,該操作只有兩態,要么完成,要么未完成

🌉互斥量mutex

  • ?部分情況,線程使?的數據都是局部變量,變量的地址空間在線程棧空間內,這種情況,變量歸屬單個線程,其他線程?法獲得這種變量。
  • 但有時候,很多變量都需要在線程間共享,這樣的變量稱為共享變量,可以通過數據的共享,完成線程之間的交互。
  • 多個線程并發的操作共享變量,會帶來?些問題。

Makefile文件

bin=ticket
cc=g++
src=$(wildcard *.cc)
obj=$(src:.cc=.o)$(bin):$(obj)$(cc) -o $@ $^ -lpthread
%.o:%.cc@echo "Comiling $< to $@"$(cc) -c $< -std=c++17.PHONY:clean
clean:rm -f $(bin) $(obj).PHONY:test
test:echo $(src)echo $(obj)

代碼:

#include <stdio.h>
#include <string>
#include <string.h>
#include <pthread.h>
#include <unistd.h>int ticket = 100;void* routine(void* args)
{char *id = (char*)args;// std::string id = static_cast<const char*>(args);while(1){if(ticket > 0){usleep(10000);printf("%s sells ticket:%d\n", id, ticket);ticket--;}else{break;}}return nullptr;
}int main(void)
{pthread_t t1, t2 , t3, t4;pthread_create(&t1, nullptr, routine, (void*)"thread 1");pthread_create(&t2, nullptr, routine, (void*)"thread 2");pthread_create(&t3, nullptr, routine, (void*)"thread 3");pthread_create(&t4, nullptr, routine, (void*)"thread 4");pthread_join(t1, nullptr);pthread_join(t2, nullptr);pthread_join(t3, nullptr);pthread_join(t4, nullptr);return 0;
}

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

  • if語句判斷條件為真以后,代碼可以并發的切換到其他進程
  • usleep這個模擬夜漫長業務的過程這個漫長的業務過程中,可能有多個線程會進入該代碼段
  • --ticket操作本身就不是一個原子操作

取出ticket–部分的匯編代碼

objdump -d a.out > test.objdump152   40064b:   8b 05 e3 04 20 00     mov       0x2004e3(%rip),%eax 
600b34 <ticket>153   400651:   83 e8 01                	 sub        $0x1,%eax
154   400654:   89 05 da 04 20 00       mov		%eax,0x2004da(%rip)  
600b34 <ticket>

--操作并不是原子操作而是對應三條匯編指令:

  • load將共享變量體的從內存加載到寄存器
  • update更新寄存器里面的只執行復議操作
  • store:將新值從寄存器寫回共享變量ticket的內存地址

要解決以上問題需要做到三點:

  • 代碼必須要有互斥行為:當代碼進入臨界區執行時,不允許其他進程進入該臨界區
  • 如果多個線程同時要求進入臨界區的代碼,并且臨界區沒有線程在執行,那么只能一個線程進入該臨界區
  • 如果現場不在臨界區中執行,那么該現場就不能阻止其他進程進入臨界區

要做到這三點,本身是上就是需要一把鎖,linux上提供這把鎖叫互斥量
在這里插入圖片描述
互斥量的接口
初始化互斥量的兩種方法

  • 方法1:靜態分配
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER 
  • ?法2,動態分配:
    int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
    參數:
    mutex:要初始化的互斥量
    attr:這是一個指向 pthread_mutexattr_t 類型對象的指針,該類型用于定義互斥鎖的屬性。如果將其設置為 NULL

銷毀互斥量
銷毀互斥量需要注意:

  • 使用PTHREAD_ MUTEX_ INITIALIZER初始化的互斥量不需要銷毀
  • 不要銷毀?個已經加鎖的互斥量
  • 已經銷毀的互斥量,要確保后?不會有線程再嘗試加鎖
int pthread_mutex_destroy(pthread_mutex_t *mutex);

互斥量加鎖和解鎖

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功返回o,失敗返回錯誤號

調用pthread_ lock時,可能會遇到以下情況:

  • 互斥量處于未鎖狀態,該函數會將互斥量鎖定,同時返回成功
  • 發起函數調用時,其他線程已經鎖定互斥量,或者存在其他線程同時申請互斥量,但沒有競爭到互斥量,那么pthread_lock調用會陷入阻塞(執行流被掛起),等待互斥量解鎖。

改進上面的售票系統:

#include <stdio.h>
#include <string>
#include <string.h>
#include <pthread.h>
#include <unistd.h>int ticket = 100;
pthread_mutex_t mutex;void* routine(void* args)
{char *id = (char*)args;// std::string id = static_cast<const char*>(args);while(1){pthread_mutex_lock(&mutex);if(ticket > 0){usleep(1000);printf("%s sells ticket:%d\n", id, ticket);ticket--;pthread_mutex_unlock(&mutex);}else{pthread_mutex_unlock(&mutex);break;}}return nullptr;
}int main(void)
{pthread_t t1, t2 , t3, t4;pthread_create(&t1, nullptr, routine, (void*)"thread 1");pthread_create(&t2, nullptr, routine, (void*)"thread 2");pthread_create(&t3, nullptr, routine, (void*)"thread 3");pthread_create(&t4, nullptr, routine, (void*)"thread 4");pthread_join(t1, nullptr);pthread_join(t2, nullptr);pthread_join(t3, nullptr);pthread_join(t4, nullptr);pthread_mutex_destroy(&mutex);return 0;
}

在這里插入圖片描述
在這里插入圖片描述

RAII風格的互斥鎖,C++11也有,比如:
std : : mutex mtx;
std : : lock_guard guard ( mtx ) ;

🌠線程同步

🌉條件變量

  • 當?個線程互斥地訪問某個變量時,它可能發現在其它線程改變狀態之前,它什么也做不了。
  • 例如?個線程訪問隊列時,發現隊列為空,它只能等待,只到其它線程將?個節點添加到隊列中。這種情況就需要?到條件變量。

🌉同步概念與競態條件

  • 同步:在保證數據安全的前提下,讓線程能夠按照某種特定的順序訪問臨界資源,從?有效避免饑餓問題,叫做同步
  • 競態條件:因為時序問題,?導致程序異常,我們稱之為競態條件。在線程場景下,這種問題也
    不難理解

🌉 條件變量函數

初始化

int pthread_cond_init(pthread_cond_t *restrict cond,   const pthread_condattr_t*restrict attr);

參數:
cond:要初始化的條件變量
attr: NULL

銷毀:

int pthread_cond_destroy(pthread_cond_t *cond)

等待條件滿?

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrictmutex);
參數:
cond:要在這個條件變量上等待
mutex:互斥量,后面詳細解釋

喚醒等待

int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

簡單案例:

  • 我們先使用PTHREAD_COND/MUTEX_INITIALIZER進行測試,對其他細節暫不追究
  • 然后將接口更改成為使用pthread_cond_init/pthread_cond_destroy的方式,方便后續進行封裝
#include <iostream>
#include <string.h>
#include <unistd.h>
#include <pthread.h>pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;void* active(void* args)
{std::string name = static_cast<const char*>(args);while(true){pthread_mutex_lock(&mutex);pthread_cond_wait(&cond, &mutex);std::cout<< name << "活動..." << std::endl;pthread_mutex_unlock(&mutex);}
}int main()
{pthread_t t1, t2;pthread_create(&t1, nullptr, active, (void*)"thread -1");pthread_create(&t2, nullptr, active, (void*)"thread -2");sleep(3);while(true){//對比測試pthread_cond_signal(&cond);//喚醒一個線程// pthread_cond_broadcast(&cond);//喚醒所有線程sleep(1);}pthread_join(t1, nullptr);pthread_join(t2, nullptr);pthread_cond_destroy(&cond);pthread_mutex_destroy(&mutex);return 0;
}

在這里插入圖片描述


🚩總結

請添加圖片描述

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

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

相關文章

MySQL索引優化,性能飆升的秘密!

0.前言 假設你經營一家電商平臺&#xff0c;某天用戶突然投訴商品搜索加載時間超過10秒。技術團隊緊急排查&#xff0c;發現一條原本執行0.1秒的查詢語句&#xff0c;在百萬級數據量下竟變成了全表掃描。這時&#xff0c;數據庫索引猶如深夜急診室里的救命儀器——它的存在與否…

基于STM32、HAL庫、HS12864(ST7920,并行接口)C語言程序設計

1、hs12864.h頭文件: #ifndef __HS12864_H #define __HS12864_H #ifdef __cplusplus extern "C" {#endif #include "stm32l4xx_hal.h" // 控制線定義 - 根據實際硬件修改 #define HS12864_RS_GPIO_PORT GPIOC #define HS12864_RS_PIN GPIO_PI…

【C語言】C語言 實踐課題選題系統(源碼+報告+數據文件)【獨一無二】

&#x1f449;博__主&#x1f448;&#xff1a;米碼收割機 &#x1f449;技__能&#x1f448;&#xff1a;C/Python語言 &#x1f449;專__注&#x1f448;&#xff1a;專注主流機器人、人工智能等相關領域的開發、測試技術。 系C語言 實踐課題選題系統&#xff08;源碼報告數據…

基于SpringBoot的“高考志愿智能推薦系統”的設計與實現(源碼+數據庫+文檔+PPT)

基于SpringBoot的“高考志愿智能推薦系統”的設計與實現&#xff08;源碼數據庫文檔PPT) 開發語言&#xff1a;Java 數據庫&#xff1a;MySQL 技術&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系統展示 系統總體結構圖 系統首頁界面 系統注冊頁…

React 低代碼項目:組件設計

React 低代碼項目&#xff1a;組件設計 Date: February 6, 2025 React表單組件 **目標&#xff1a;**使用 Ant Design 表單組件&#xff0c;開發登錄、注冊、搜索功能 內容&#xff1a; 使用 React 表單組件、受控組件使用 Ant Design 表單組件使用 表單組件的校驗和錯誤提…

深入剖析 Vue 的響應式原理:構建高效 Web 應用的基石

深入剖析 Vue 的響應式原理&#xff1a;構建高效 Web 應用的基石 在前端開發的廣闊天地里&#xff0c;Vue.js 憑借其簡潔易用的特性和強大的功能&#xff0c;成為眾多開發者的心頭好。其中&#xff0c;響應式原理作為 Vue 的核心亮點之一&#xff0c;讓數據與視圖之間實現了高…

QCustomplot庫運用

最近需要用到這個庫顯示數據&#xff0c;需要在一個曲線圖4個Y軸共用一個X軸&#xff0c;并且做游標&#xff0c;跟隨鼠標移動&#xff0c;并且實時反饋數據到表格中。記錄一下程序。 customPlot new QCustomPlot(this); customPlot->setBackground(QBrush(QColor(204,204,…

STM32 串口 (DMA + 空閑中斷 + 環形緩沖區)

STM32 串口 &#xff08;DMA 空閑中斷 環形緩沖區&#xff09; 1. 基本概念 UART 空閑中斷&#xff08;IDLE&#xff09;&#xff1a; 當串口 RX 線上 連續一段時間沒有數據接收&#xff0c;USART 外設觸發 空閑中斷。空閑中斷的主要作用是通知數據傳輸完成或當前幀結束。 D…

股指期貨是什么?股指期貨日內拐點有什么特征?

股指期貨是一種金融衍生品&#xff0c;股指期貨日內拐點就是在一天交易過程中&#xff0c;市場走勢發生顯著改變的那個點。 股指期貨是什么&#xff1f; 股指是一個指數&#xff0c;比如上證50指數、滬深300指數、中證500指數以及中證1000指數&#xff0c;這是一堆股票的一個整…

Opensearch/ElasticSearch-ctx查詢內容不全的問題

問題 在OpenSearch中&#xff0c;我希望在action中把一整條log作為報警內容發送出來&#xff0c;但是根據文檔&#xff0c;配置為ctx.results.0.hits.hits.0._source.log&#xff0c;但是發現根本找不到這個值 經過查詢&#xff0c;我發現在返回的ctx中僅存在如下的值 resul…

vue2和vue3插槽slot最通俗易懂的區別理解

在 Vue 的組件通信中&#xff0c;slot&#xff08;插槽&#xff09;的編譯優化是一個重要的性能提升點。以下是 Vue2 和 Vue3 在 slot 處理上的差異及優化原理&#xff0c;用更直觀的方式解釋&#xff1a; Vue2 的 Slot 更新機制 想象一個父子組件場景&#xff1a; 父組件&am…

【16屆藍橋杯寒假刷題營】第1期DAY4

1.披薩和西藍花 - 藍橋云課 1. 披薩和西藍花 問題描述 在接下來的 N 天里&#xff08;編號從 1 到 N&#xff09;&#xff0c;坤坤計劃烹飪披薩或西蘭花。他寫下一個長度為 N 的字符串 A&#xff0c;對于每個有效的 i&#xff0c;如果字符 Ai 是 1&#xff0c;那么他將在第 i…

你需要了解的遠程登錄協議——Telnet

你需要了解的遠程登錄協議——Telnet 一. 什么是Telnet&#xff1f;二. Telnet的優缺點三. Telnet vs SSH&#xff1a;哪一個更適合&#xff1f;四. Telnet的應用場景 前言 點個免費的贊和關注&#xff0c;有錯誤的地方請指出&#xff0c;看個人主頁有驚喜。 作者&#xff1a;神…

本地部署【LLM-deepseek】大模型 ollama+deepseek/conda(python)+openwebui/docker+openwebui

通過ollama本地部署deepseek 總共兩步 1.模型部署 2.[web頁面] 參考官網 ollama:模型部署 https://ollama.com/ open-webui:web頁面 https://github.com/open-webui/open-webui 設備參考 Mac M 芯片 windows未知 蒸餾模型版本:deepseek-r1:14b 運行情況macminim2 24256 本地…

PHP在線題庫小程序

&#x1f4da; 在線題庫小程序&#xff1a;學習提分新神器&#xff0c;輕松躍升學霸行列 這是一款專為追夢學子精心策劃、基于ThinkPHPUniApp框架匠心打造的在線題庫類微信小程序系統。它宛如一把?智慧鑰匙?&#xff0c;為追求高效學習的你解鎖&#x1f513;知識寶庫的大門。…

Java開發中的連接池技術介紹

連接池技術是Java開發中用于管理數據庫連接的重要技術&#xff0c;尤其在SSM&#xff08;Spring、Spring MVC、MyBatis&#xff09;架構中&#xff0c;連接池能夠顯著提升數據庫操作的性能和資源利用率。下面我們將詳細介紹連接池技術解決的問題、配置方案以及代碼實現。 1. 連…

Unity-Mirror網絡框架-從入門到精通之Pong示例

文章目錄 前言示例介紹NetworkManagerPongBallPlayer總結前言 在現代游戲開發中,網絡功能日益成為提升游戲體驗的關鍵組成部分。本系列文章將為讀者提供對Mirror網絡框架的深入了解,涵蓋從基礎到高級的多個主題。Mirror是一個用于Unity的開源網絡框架,專為多人游戲開發設計…

布隆過濾器到底是什么東西?它有什么用

布隆過濾器&#xff1a;用概率換空間的奇妙數據結構 引言&#xff1a;當空間成為奢侈品 在互聯網每天產生2.5萬億字節數據的時代&#xff0c;Google每秒處理超過9萬次搜索請求&#xff0c;Redis緩存系統支撐著百萬級QPS的訪問。面對如此海量的數據處理需求&#xff0c;傳統的…

任務1 將單表中的單個rfid增加為多個rfid

方案 使用連表查詢解決 單獨創建一個rfid的表 讓tool_id對應多個rfid 需要優化的表 1&#xff1a;tool_materials_stock 庫存管理 已完成 數據遷移完成 原庫rfid字段未刪除 2&#xff1a;tool_borrow_return 借出借還管理 已完成 3&#xff1a;too…

OutSystems Platform Tools Platform Services

概述&#xff08;Overview&#xff09; outsystems是一整套低代碼的企業級應用&#xff08;WEB 和 移動端&#xff09;的開發環境。 本文主要講解outsystems的Platform Tools與Platform Services 平臺工具&#xff08;Platform Tools&#xff09; 集成開發環境IDE&#xff0…