国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Linux】線程同步

這篇具有很好參考價(jià)值的文章主要介紹了【Linux】線程同步。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

條件變量相關(guān)函數(shù)

初始化條件變量-pthread_cond_init

初始化條件變量的函數(shù)叫做pthread_cond_init

#include<pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

參數(shù)說明

cond:需要初始化的條件變量

attr:初始化條件變量的屬性,一般設(shè)置為NULL

返回值說明

初始化成功返回0,失敗返回錯(cuò)誤碼


注意:調(diào)用pthread_cond_init函數(shù)初始化條件變量叫做動(dòng)態(tài)分配,我們還可以用靜態(tài)分配的方式初始化條件變量

pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

銷毀條件變量-pthread_cond_destroy

銷毀條件變量的函數(shù)叫做pthread_cond_destroy

#include<pthread.h>
int pthread_cond_destroy(pthread_cond_t *cond);

參數(shù)說明

cond:需要銷毀的條件變量

返回值說明

銷毀成功返回0,失敗返回錯(cuò)誤碼


注意:使用PTHREAD_COND_INITIALIZER初始化 (靜態(tài)分配)的條件變量不需要銷毀


等待條件變量-pthread_cond_wait

等待條件變量滿足的函數(shù)叫做pthread_cond_wait

#include<pthread.h>
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);

參數(shù)說明

cond:需要等待的條件變量

mutex:當(dāng)前線程所處臨界區(qū)對(duì)應(yīng)的互斥鎖

返回值說明

函數(shù)調(diào)用成功返回0,失敗返回錯(cuò)誤碼


喚醒等待條件變量

喚醒等待的函數(shù)有以下兩個(gè)

pthread_cond_broadcast
#include<pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);
pthread_cond_signal
#include<pthread.h>
int pthread_cond_signal(pthread_cond_t *cond);

參數(shù)說明

cond:?jiǎn)拘言赾ond條件變量下等待的線程

返回值說明

函數(shù)調(diào)用成功返回0,失敗返回錯(cuò)誤碼


區(qū)別

  • pthread_cond_signal函數(shù)用于喚醒等待隊(duì)列中首個(gè)線程
  • pthread_cond_broadcast函數(shù)用于喚醒等待隊(duì)列中的全部線程

小例子

下面我們用主線程創(chuàng)建三個(gè)新線程,讓主線程控制這三個(gè)新線程, 這三個(gè)新線程創(chuàng)建后都在條件變量下進(jìn)行等待,直到被主線程喚醒

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

pthread_mutex_t mtx;//互斥鎖
pthread_cond_t cond;//條件變量

//主線程控制新線程
void *ctrl(void *args)
{
    std::string name = (char*)args;
    while(1)
    {
        std::cout << "master say : begin work" << std::endl;
        //pthread_cond_signal函數(shù)作用:喚醒在條件變量下等待的 一個(gè) 線程
        //哪一個(gè)呢?當(dāng)前在等待隊(duì)列里等待的第一個(gè)線程
        pthread_cond_signal(&cond); 
        sleep(2);
    }
}
void *work(void *args)
{
    int number = *(int*)args;
    delete (int*)args;
    while(1)
    {
        pthread_cond_wait(&cond, &mtx);//等待條件變量
        std::cout << "worker: " << number << " is working ..." << std::endl;
    }
}
#define NUM 3
int main()
{
    pthread_mutex_init(&mtx, nullptr);//初始化這把鎖
    pthread_cond_init(&cond, nullptr);//初始化條件變量
    pthread_t master;
    pthread_t worker[NUM];
    pthread_create(&master, nullptr, ctrl, (void*)"boss");
    //創(chuàng)建NUM個(gè)線程
    for(int i = 0; i < NUM; i++)
    {
        int *number = new int(i);
        pthread_create(worker+i, nullptr, work, (void*)number);
    }
    //線程等待
    for(int i = 0; i < NUM; i++)
    {
        pthread_join(worker[i], nullptr);
    }

    pthread_join(master, nullptr);//線程等待
    
    pthread_mutex_destroy(&mtx);//釋放鎖
    pthread_cond_destroy(&cond);//釋放條件變量
    return 0;
}

此時(shí)我們會(huì)發(fā)現(xiàn)喚醒這三個(gè)線程時(shí)具有明顯的順序性

根本原因是當(dāng)這若干個(gè)線程啟動(dòng)時(shí)默認(rèn)都會(huì)在該條件變量下去等待,而我們每次都喚醒的是在當(dāng)前條件變量下等待的頭部線程,當(dāng)該線程執(zhí)行完打印操作后會(huì)繼續(xù)排到等待隊(duì)列的尾部進(jìn)行wait,所以我們能夠看到一個(gè)周轉(zhuǎn)的現(xiàn)象

【Linux】線程同步


如果我們想每次喚醒都將在該條件變量下等待的所有線程進(jìn)行喚醒,可以將代碼中的pthread_cond_signal函數(shù)改為pthread_cond_broadcast函數(shù)

//主線程控制新線程
void *ctrl(void *args)
{
    std::string name = (char*)args;
    while(1)
    {
        std::cout << "master say : begin work" << std::endl;
        pthread_cond_broadcast(&cond);
        sleep(2);
    }
}

此時(shí)我們每一次喚醒都會(huì)將所有在該條件變量下等待的線程進(jìn)行喚醒==>也就是每次都將這三個(gè)線程喚醒

【Linux】線程同步


關(guān)于等待函數(shù)的補(bǔ)充

為什么pthread_cond_wait函數(shù)的第二個(gè)參數(shù)需要傳入互斥量

1)條件等待是線程間同步的一種手段,如果只有一個(gè)線程,條件不滿足,一直等下去都不會(huì)滿足,所以必須要有一個(gè)線程通過某些操作,改變共享變量,使原先不滿足的條件變得滿足,并且友好的通知等待在條件變量上的線程

2)條件不會(huì)無緣無故的突然變得滿足了,必然會(huì)牽扯到共享數(shù)據(jù)的變化,所以一定要用互斥鎖來保護(hù),沒有互斥鎖就無法安全的獲取和修改共享數(shù)據(jù)

【Linux】線程同步

3)當(dāng)線程進(jìn)入臨界區(qū)時(shí)需要先加鎖,然后判斷內(nèi)部資源的情況,若不滿足當(dāng)前線程的執(zhí)行條件,則需要在該條件變量下進(jìn)行等待,但此時(shí)該線程是拿著鎖被掛起的,也就意味著這個(gè)鎖再也不會(huì)被釋放了,此時(shí)就會(huì)發(fā)生死鎖問題

4)所以在調(diào)用pthread_cond_wait函數(shù)時(shí),還需要將對(duì)應(yīng)的互斥鎖傳入,此時(shí)當(dāng)線程因?yàn)槟承l件不滿足需要在該條件變量下進(jìn)行等待時(shí),就會(huì)自動(dòng)釋放該互斥鎖

5)當(dāng)該線程被喚醒時(shí),該線程會(huì)接著執(zhí)行臨界區(qū)內(nèi)的代碼,此時(shí)便要求該線程必須立馬獲得對(duì)應(yīng)的互斥鎖,因此當(dāng)某一個(gè)線程被喚醒時(shí),實(shí)際會(huì)自動(dòng)獲得對(duì)應(yīng)的互斥鎖


總結(jié):

  • 當(dāng)該線程進(jìn)入等待的時(shí)候,互斥鎖會(huì)自動(dòng)釋放,而當(dāng)該線程被喚醒時(shí),又會(huì)自動(dòng)獲得對(duì)應(yīng)的互斥鎖
  • 條件變量需要配合互斥鎖使用,其中條件變量是用來完成同步的,而互斥鎖是用來完成互斥的
  • pthread_cond_wait函數(shù)有兩個(gè)功能,一就是讓線程在特定的條件變量下等待,二就是讓線程釋放對(duì)應(yīng)的互斥鎖

我們可以不可以:當(dāng)我們進(jìn)入臨界區(qū)上鎖后,如果發(fā)現(xiàn)條件不滿足,先解鎖,然后在該條件變量下進(jìn)行等待

即:

//錯(cuò)誤的設(shè)計(jì)
pthread_mutex_lock(&mutex);
while (condition_is_false){
	pthread_mutex_unlock(&mutex);//解鎖
	//解鎖之后,等待之前,條件可能已經(jīng)滿足,信號(hào)已經(jīng)發(fā)出,但是該信號(hào)可能被錯(cuò)過
	pthread_cond_wait(&cond);
	pthread_mutex_lock(&mutex);//再加鎖
}
pthread_mutex_unlock(&mutex);//解鎖

不可行!因?yàn)?strong>解鎖和等待不是原子操作,調(diào)用解鎖之后,在調(diào)用pthread_cond_wait函數(shù)之前,如果已經(jīng)有其他線程獲取到互斥量,發(fā)現(xiàn)此時(shí)條件滿足,于是發(fā)送了信號(hào),那么此時(shí)pthread_cond_wait函數(shù)將錯(cuò)過這個(gè)信號(hào),最終可能會(huì)導(dǎo)致線程永遠(yuǎn)不會(huì)被喚醒,因此解鎖和等待必須是一個(gè)原子操作

進(jìn)入pthread_cond_wait函數(shù)后,會(huì)先判斷條件變量是否等于0,若等于0則說明不滿足,此時(shí)會(huì)先將對(duì)應(yīng)的互斥鎖解鎖,直到pthread_cond_wait函數(shù)返回時(shí)再將條件變量改為1,并將對(duì)應(yīng)的互斥鎖加鎖


條件變量使用規(guī)范

等待條件變量的代碼

pthread_mutex_lock(&mutex);//加鎖
while (條件為假)
	pthread_cond_wait(&cond, &mutex);//條件不滿足,就一直等待
修改條件
pthread_mutex_unlock(&mutex);//解鎖

喚醒等待線程的代碼文章來源地址http://www.zghlxwxcb.cn/news/detail-464780.html

pthread_mutex_lock(&mutex);//加鎖
設(shè)置條件為真
pthread_cond_signal(&cond);//滿足條件了,喚醒在條件變量等待隊(duì)列當(dāng)中的第一個(gè)線程
pthread_mutex_unlock(&mutex);//解鎖

到了這里,關(guān)于【Linux】線程同步的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Linux系統(tǒng)編程:線程】 線程控制 -- 創(chuàng)建、終止、等待、分離 | 線程互斥與同步 | 互斥量與條件變量 | 生產(chǎn)者消費(fèi)者模型 | 線程池 | STL/智能指針與線程安全 | 讀者寫者模型

    【Linux系統(tǒng)編程:線程】 線程控制 -- 創(chuàng)建、終止、等待、分離 | 線程互斥與同步 | 互斥量與條件變量 | 生產(chǎn)者消費(fèi)者模型 | 線程池 | STL/智能指針與線程安全 | 讀者寫者模型

    寫在前面 本文重點(diǎn): 了解線程概念,理解線程與進(jìn)程區(qū)別與聯(lián)系。 學(xué)會(huì)線程控制,線程創(chuàng)建,線程終止,線程等待。 了解線程分離與線程安全。 學(xué)會(huì)線程同步。 學(xué)會(huì)使用互斥量,條件變量,posix 信號(hào)量,以及讀寫鎖。 理解基于讀寫鎖的讀者寫者問題。 一、線程概念 ??

    2024年02月04日
    瀏覽(104)
  • 4.【CPP】入門(初始化列表||explicit||static||友元||靜態(tài)成員變量/函數(shù))

    4.【CPP】入門(初始化列表||explicit||static||友元||靜態(tài)成員變量/函數(shù))

    我們知道在c++11中才能在成員對(duì)象聲明時(shí)初始化,像下面這樣。 注意:構(gòu)造函數(shù)不是初始化,而是賦初始值。那么在c++11以前該怎么初始化成員變量呢? 每個(gè)成員變量在初始化列表中只能出現(xiàn)一次(初始化只能初始化一次) 類中包含以下成員,必須放在初始化列表位置進(jìn)行初始

    2024年01月20日
    瀏覽(28)
  • Linux--線程-條件控制實(shí)現(xiàn)線程的同步

    Linux--線程-條件控制實(shí)現(xiàn)線程的同步

    1.條件變量 條件變量是線程另一可用的同步機(jī)制。條件變量給多個(gè)線程提供了一個(gè)會(huì)合的場(chǎng)所。條件變量與互斥量一起使用時(shí),允許線程以無競(jìng)爭(zhēng)的方式等待特定的條件發(fā)生。 條件本身是由互斥量保護(hù)的。線程在改變條件狀態(tài)前必須首先鎖住互斥量,其他線程在獲得互斥量之

    2024年02月05日
    瀏覽(23)
  • 七、初始化環(huán)境變量

    void env_relocate (void) { if (gd-env_valid == 0) { puts (\\\"*** Warning - bad CRC, using default environmentnn\\\"); show_boot_progress (-60); set_default_env(); } else { env_relocate_spec (); } gd-env_addr = (ulong)(env_ptr-data); } void env_relocate_spec (void) { #if !defined(ENV_IS_EMBEDDED) int ret; ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr); if

    2023年04月09日
    瀏覽(25)
  • kotlin 初始化變量

    2024年02月16日
    瀏覽(18)
  • golang變量初始化順序

    順序: 1.引用的包 2.全局變量 3.init()函數(shù) 4.main()函數(shù) 輸出 $ go run 1.go pkg init func() main init main()

    2024年04月17日
    瀏覽(36)
  • pthread 變量靜態(tài)初始化 避免使用被銷毀過的變量

    互斥鎖: pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; 讀寫鎖: pthread_rwlock_t g_rwlock = PTHREAD_RWLOCK_INITIALIZER; 條件變量: pthread_cond_t g_cond = PTHREAD_COND_INITIALIZER; 以互斥鎖為例,當(dāng)持有互斥鎖的線程,需要進(jìn)行互斥鎖的銷毀工作時(shí),無法確保當(dāng)前沒有任何其他線程會(huì)在鎖銷毀之后,仍

    2024年02月06日
    瀏覽(28)
  • 【JavaScript】JavaScript 變量 ① ( JavaScript 變量概念 | 變量聲明 | 變量類型 | 變量初始化 | ES6 簡(jiǎn)介 )

    【JavaScript】JavaScript 變量 ① ( JavaScript 變量概念 | 變量聲明 | 變量類型 | 變量初始化 | ES6 簡(jiǎn)介 )

    JavaScript 變量 是用于 存儲(chǔ)數(shù)據(jù) 的 容器 , 通過 變量名稱 , 可以 獲取 / 修改 變量 中的數(shù)據(jù) ; 變量 的 本質(zhì) 是 存放數(shù)據(jù) 的 一塊內(nèi)存空間 ; 在 JavaScript 中, 使用 var / let / const 來聲明變量 , 每個(gè)變量都有一個(gè) 變量名 和 一個(gè) 變量值 ; JavaScript 變量聲明 : var : 使用

    2024年03月15日
    瀏覽(31)
  • go語言包、變量、init初始化順序

    go語言包、變量、init初始化順序

    一個(gè)完整的 go 語言可運(yùn)行程序,通常會(huì)包含引用的包、變量、init 函數(shù)以及 main 函數(shù)幾個(gè)部分。 包、變量、常量、init 函數(shù)以及 main 函數(shù)初始化順序如下圖所示: 在一個(gè) go 語言程序中,初始化順序規(guī)則如下: 引入的包 當(dāng)前包中的變量、常量 當(dāng)前包的 init 函數(shù) main 函數(shù) 初始

    2023年04月14日
    瀏覽(26)
  • 【Golang入門教程】Go語言變量的初始化

    【Golang入門教程】Go語言變量的初始化

    強(qiáng)烈推薦 前些天發(fā)現(xiàn)了一個(gè)巨牛的人工智能學(xué)習(xí)網(wǎng)站,通俗易懂,風(fēng)趣幽默,忍不住分享一下給大家。點(diǎn)擊跳轉(zhuǎn)到網(wǎng)站: 人工智能 推薦一個(gè)個(gè)人工作,日常中比較常用的人工智能工具,無需魔法,忍不住分享一下給大家。點(diǎn)擊跳轉(zhuǎn)到網(wǎng)站: 人工智能工具 引言 在Go語言中,變量

    2024年04月17日
    瀏覽(105)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包