亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Linux中的線程安全與線程同步詳解

 更新時(shí)間:2025年04月27日 09:38:43   作者:s_little_monster_  
這篇文章主要介紹了Linux中的線程安全與線程同步,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一、線程安全

1、概念

我們這里通過理解重入與線程安全的關(guān)系來理解線程安全

線程安全多個(gè)線程并發(fā)同一段代碼時(shí),不會(huì)出現(xiàn)不同的結(jié)果 

重入同一個(gè)函數(shù)被不同的執(zhí)行流調(diào)用,當(dāng)前一個(gè)流程還沒有執(zhí)行完,就有其他的執(zhí)行流再次進(jìn)入,一個(gè)函數(shù)在重入的情況下運(yùn)行結(jié)果不會(huì)出現(xiàn)任何問題,這樣的函數(shù)稱為可重入函數(shù),否則,就是不可重入函數(shù)

2、常見線程情況

常見線程不安全情況

  • 不保護(hù)共享變量的函數(shù)
  • 函數(shù)狀態(tài)隨著被調(diào)用,狀態(tài)發(fā)生變化的函數(shù)
  • 返回指向靜態(tài)變量指針的函數(shù)
  • 調(diào)用線程不安全函數(shù)的函數(shù)

常見線程安全情況

  • 每個(gè)線程對(duì)全局變量或靜態(tài)變量只有讀權(quán)限沒有寫權(quán)限
  • 類或接口對(duì)于線程來說是原子操作
  • 多個(gè)線程之間的切換不會(huì)導(dǎo)致該接口的執(zhí)行結(jié)果存在二義性

3、常見重入情況

常見不可重入情況

  • 調(diào)用了malloc或new函數(shù),因?yàn)閙alloc函數(shù)是用全局鏈表來管理堆的
  • 調(diào)用了標(biāo)準(zhǔn)IO庫(kù)函數(shù),標(biāo)準(zhǔn)IO庫(kù)中很多實(shí)現(xiàn)都以不可重入的方式使用全局?jǐn)?shù)據(jù)結(jié)構(gòu)
  • 可重入函數(shù)體內(nèi)使用了靜態(tài)的數(shù)據(jù)結(jié)構(gòu)

常見可重入情況

  • 不使用全局和靜態(tài)變量
  • 不使用malloc或new出來的空間
  • 不調(diào)用不可重入函數(shù)
  • 不返回靜態(tài)或全局?jǐn)?shù)據(jù),所有數(shù)據(jù)都由函數(shù)的調(diào)用者提供
  • 使用本地?cái)?shù)據(jù),或者通過制作全局?jǐn)?shù)據(jù)的本地拷貝來保護(hù)全局?jǐn)?shù)據(jù)

4、可重入與線程安全

聯(lián)系

  • 函數(shù)可重入就代表著線程安全
  • 函數(shù)不可重入,那就不能由多個(gè)線程使用,有可能引發(fā)線程安全問題
  • 如果一個(gè)函數(shù)中有全局變量,這么這個(gè)函數(shù)既是不可重入的又不是線程安全的

區(qū)別

  • 可重入函數(shù)是線程安全函數(shù)的一種
  • 線程安全不一定是可重入的,但可重入的一定是線程安全的
  • 如果將對(duì)臨界資源的訪問加上鎖,那么這個(gè)函數(shù)是線程安全的,但如果這個(gè)重入函數(shù)的鎖還沒釋放則會(huì)產(chǎn)生死鎖,因此是不可重入的

5、死鎖

(一)概念

死鎖是指在一組進(jìn)程或線程中的各個(gè)進(jìn)程或線程均占有不會(huì)釋放的資源,但因互相申請(qǐng)被其他進(jìn)程或線程所占用的不會(huì)釋放的資源而處于的一種永久等待的狀態(tài)

死鎖都是人為產(chǎn)生的,我們可以規(guī)避掉的

(二)死鎖的四個(gè)必要條件

  • 互斥條件:一個(gè)資源只能被一個(gè)執(zhí)行流使用
  • 請(qǐng)求與保持條件:一個(gè)執(zhí)行流因請(qǐng)求資源而阻塞時(shí),對(duì)已獲得的資源保持不放
  • 不剝奪條件:一個(gè)執(zhí)行流已獲得的資源在未使用完之前。不能強(qiáng)行剝奪
  • 循環(huán)等待條件:若干執(zhí)行流之間形成一種頭尾相接的循環(huán)等待資源的關(guān)系

(三)避免死鎖的方法

  • 當(dāng)有死鎖的時(shí)候,必然是滿足上面這四個(gè)條件的,但滿足上面四個(gè)條件不一定形成死鎖,我們只要破壞上面其中任何一條條件就可以避免死鎖
  • 加鎖順序一致
  • 避免鎖未釋放的場(chǎng)景
  • 資源一次性分配

二、線程同步

1、概念

在純互斥的場(chǎng)景下,由于我們的鎖只有少量個(gè),多個(gè)線程同時(shí)競(jìng)爭(zhēng)鎖,但是得到鎖的只有一小部分線程,剩下的線程就會(huì)因?yàn)榈却?,產(chǎn)生 “線程饑餓” 問題,線程饑餓本質(zhì)上就是搶奪不到鎖的線程,即搶奪不到資源的線程在等待鎖的釋放,為了避免這里的饑餓的問題,我們就通過線程同步來在保證數(shù)據(jù)安全的前提下,讓線程按照順序訪問臨界資源

2、條件變量

(一)概念

當(dāng)一個(gè)線程互斥的訪問某個(gè)變量時(shí),它可能在其他線程改變狀態(tài)之前什么也做不了,比如一個(gè)線程訪問隊(duì)列時(shí),發(fā)現(xiàn)隊(duì)列為空,那么它只能等待,直到其他進(jìn)程將一個(gè)節(jié)點(diǎn)添加到隊(duì)列當(dāng)中,這個(gè)時(shí)候我們就可以利用條件變量來規(guī)避這種情況

(二)調(diào)用函數(shù)

(1)初始化條件變量
#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
  • 返回值:成功返回0,失敗返回非0錯(cuò)誤碼
  • cond:指向要初始化的條件變量的指針,pthread_cond_t 是一個(gè)表示條件變量的數(shù)據(jù)類型
  • attr:指向條件變量屬性對(duì)象的指針,傳入NULL表示使用默認(rèn)屬性
(2)銷毀條件變量
#include <pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);
  • 返回值:成功返回0,失敗返回非0錯(cuò)誤碼
  • cond:指向要銷毀的條件變量的指針
(3)等待條件被滿足
#include <pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
  • 返回值:成功返回0,失敗返回非0錯(cuò)誤碼
  • cond:指向要操作的條件變量的指針,條件變量用于線程之間的等待和通知機(jī)制
  • mutex:指向互斥鎖的指針,互斥鎖用于保護(hù)共享資源,確保線程安全

調(diào)用該函數(shù)時(shí),線程會(huì)自動(dòng)釋放互斥鎖mutex,以便其他線程可以獲取鎖,當(dāng)收到信號(hào)被喚醒后,線程會(huì)重新嘗試獲取互斥鎖

(4)喚醒等待線程
#include <pthread.h>
//喚醒一個(gè)等待線程
int pthread_cond_signal(pthread_cond_t *cond);
//喚起所有等待線程
int pthread_cond_broadcast(pthread_cond_t *cond);
  • 返回值:成功返回0,失敗返回非0錯(cuò)誤碼
  • cond:指向要操作的條件變量的指針,條件變量是一種用于線程同步的機(jī)制,允許線程在某個(gè)條件不滿足時(shí)阻塞,直到其他線程通知該條件已經(jīng)滿足

如果一個(gè)線程執(zhí)行 pthread_cond_broadcast,它會(huì)將所有等待該條件變量的線程全部喚醒,若執(zhí)行 pthread_cond_signal,則只會(huì)喚醒至少一個(gè)等待該條件變量的線程,而非只喚醒當(dāng)前線程

(三)樣例

#include <iostream>
#include <pthread.h>
#include <vector>
#include <unistd.h>

using namespace std;

#define NUM 4

int cnt = 0;
//條件變量函數(shù)的用法幾乎與鎖函數(shù)的用法完全等同
//定義全局鎖和全局條件變量
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

void *Count(void *args)
{
    pthread_detach(pthread_self()); // 線程分離,跑完就不管了,不在乎它的返回值
	// Linux是64位機(jī),指針是8字節(jié),uint是unsigned long long int   
    uint64_t num = (uint64_t)args;
    cout << "Thread " << num << " is creat success" << endl;
    usleep(100000);
    while (true)
    {
        pthread_mutex_lock(&lock);
        
        //這里pthread_cond_wait要在臨界區(qū)的原因是:
        //因?yàn)?pthread_cond_wait 是讓線程去等待,等待的原因一定是臨界資源不就緒
        //而臨界資源是否就緒,是通過判斷得來的,判斷也是訪問臨界資源,所以判斷必須在加鎖之后
        pthread_cond_wait(&cond, &lock); 
        //線程在此處進(jìn)入等待狀態(tài),等待條件變量 cond 發(fā)出信號(hào)
        
        cout << "Thread " << num << " is running... cnt: " << cnt << endl;
        cnt++;
        usleep(10000);
        pthread_mutex_unlock(&lock);
    }
}

int main()
{
    for (uint64_t i = 1; i <= NUM; i++)
    {
        pthread_t tid;
        //這里的第四個(gè)參數(shù),如果想要與新線程共享這個(gè)參數(shù)的話,可以設(shè)為(void*)&i,進(jìn)行傳址調(diào)用
        //我們這里要傳值調(diào)用,不能讓它用i
        pthread_create(&tid, nullptr, Count, (void *)i);
        usleep(1000);
    }
	//指定喚醒線程來訪問臨界資源
    while (true)
    {
        sleep(1);
        pthread_cond_signal(&cond); // 喚醒一個(gè)線程
        cout << "signal one thread..." << endl;
    }
    return 0;
}

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Jexus 5.8.2正式發(fā)布! 為Asp.Net Core生產(chǎn)環(huán)境提供平臺(tái)支持

    Jexus 5.8.2正式發(fā)布! 為Asp.Net Core生產(chǎn)環(huán)境提供平臺(tái)支持

    Jexus 5.8.2正式發(fā)布!Jexus支持ASP.NET、PHP為特色的集高安全性和高性能為一體的WEB服務(wù)器和反向代理服務(wù)器,感興趣的小伙伴們可以參考一下
    2017-06-06
  • Xshell7遠(yuǎn)程連接失敗(connection failed)的問題解決

    Xshell7遠(yuǎn)程連接失敗(connection failed)的問題解決

    本文主要介紹了Xshell7遠(yuǎn)程連接失敗(connection failed)的問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Linux 內(nèi)核通用鏈表學(xué)習(xí)小結(jié)

    Linux 內(nèi)核通用鏈表學(xué)習(xí)小結(jié)

    本篇文章主要介紹了Linux 內(nèi)核通用鏈表學(xué)習(xí)小結(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-11-11
  • Linux進(jìn)程終止的N種方式詳解

    Linux進(jìn)程終止的N種方式詳解

    進(jìn)程終止是操作系統(tǒng)中,進(jìn)程的一個(gè)重要階段,他標(biāo)志著進(jìn)程生命周期的結(jié)束,下面小編為大家整理了一些常見的Linux進(jìn)程終止方式,大家可以根據(jù)需求選擇
    2025-03-03
  • Linux使用dd命令來復(fù)制和轉(zhuǎn)換數(shù)據(jù)的操作方法

    Linux使用dd命令來復(fù)制和轉(zhuǎn)換數(shù)據(jù)的操作方法

    Linux 中的 dd 命令是一個(gè)功能強(qiáng)大的數(shù)據(jù)復(fù)制和轉(zhuǎn)換實(shí)用程序,它以較低級(jí)別運(yùn)行,通常用于創(chuàng)建可啟動(dòng)的 USB 驅(qū)動(dòng)器、克隆磁盤和生成隨機(jī)數(shù)據(jù)等任務(wù),本文給大家介紹了Linux 如何使用dd命令來復(fù)制和轉(zhuǎn)換數(shù)據(jù),需要的朋友可以參考下
    2025-01-01
  • CentOS7系統(tǒng)增加swap的操作方法實(shí)例

    CentOS7系統(tǒng)增加swap的操作方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于CentOS7系統(tǒng)增加swap的操作方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用CentOS7系統(tǒng)具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • 解析linux或android添加文件系統(tǒng)的屬性接口的方法

    解析linux或android添加文件系統(tǒng)的屬性接口的方法

    這篇文章主要介紹了linux或android添加文件系統(tǒng)的屬性接口的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-03-03
  • linux中pip操作時(shí)的超時(shí)解決方法

    linux中pip操作時(shí)的超時(shí)解決方法

    在本文中我們給大家講述了linux中pip操作時(shí)的超時(shí)解決方法以及相關(guān)注意點(diǎn),有興趣的朋友們參考下。
    2018-09-09
  • ubuntu (linux)修改網(wǎng)卡名稱命令

    ubuntu (linux)修改網(wǎng)卡名稱命令

    這篇文章主要介紹了ubuntu (linux)修改網(wǎng)卡名稱命令的相關(guān)資料,這里提供了實(shí)現(xiàn)的命令代碼,需要的朋友可以參考下
    2016-11-11
  • Linux查看服務(wù)器硬件信息的方法步驟

    Linux查看服務(wù)器硬件信息的方法步驟

    這篇文章主要介紹了Linux查看服務(wù)器硬件信息的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12

最新評(píng)論