色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

怎樣才能在不加鎖的情況下解決多線程問題

jf_78858299 ? 來源:碼農(nóng)的荒島求生 ? 作者:碼農(nóng)的荒島求生 ? 2023-03-02 09:31 ? 次閱讀

我們知道,多線程同時(shí)修改共享變量時(shí)會出現(xiàn)數(shù)據(jù)不一致的問題,比如多個(gè)線程同時(shí)對一個(gè)變量加1,假設(shè)count的初始值為0:

int count;
void add() { ++count;}

如果只有一個(gè)線程調(diào)用add函數(shù),那么什么問題都沒有,但如果多個(gè)線程同時(shí)調(diào)用上述函數(shù),比如10個(gè)線程都調(diào)用一遍,那么count值最后不一定等于0,原因在于對 count加1的操作不是原子的

所謂某個(gè)操作是原子的是指CPU要么執(zhí)行該操作,要么不執(zhí)行該操作,不存在中間狀態(tài),但上述對count加1的操作經(jīng)過編譯器處理后會生成幾條對應(yīng)的機(jī)器指令,所以該操作不是原子的。

那么怎樣才能讓其變成原子的呢?很簡單,加一把鎖。

int count;mutex mtx; // 鎖
void add() { mtx.lock(); ++count; mtx.unlock();};

現(xiàn)在我們用一把鎖將對count的操作保護(hù)了起來,此時(shí)你可以將mtx.lock()以及mtx.unlock()中間的代碼看成原子的,CPU要完全執(zhí)行完對count的加1要么根本不會操作count,這樣上述程序的運(yùn)行結(jié)果就是我們想要的了。

這是怎樣做到呢?這就要說到操作系統(tǒng)了,千萬不要小瞧了上面的mutex這把鎖,這把鎖的背后相當(dāng)復(fù)雜,因?yàn)檫@涉及到了操作系統(tǒng)。

假設(shè)現(xiàn)在有三個(gè)線程,各自運(yùn)行在不同的CPU核心上,每個(gè)方框代表一個(gè)時(shí)間片:

圖片

T1時(shí)間片這三個(gè)線程都在調(diào)用add函數(shù),線程A拿到鎖,A可以繼續(xù)向前推進(jìn),但B和C就沒這么幸運(yùn)了,此時(shí)操作系統(tǒng)將剝奪線程B和C繼續(xù)持有CPU的權(quán)利,將其分配給其它具備執(zhí)行條件的線程,這就是操作系統(tǒng)中所謂的掛起,注意,這個(gè)過程相當(dāng)復(fù)雜,因?yàn)檫@涉及到用戶態(tài)與內(nèi)核態(tài)的切換以及線程的切換等等。

此時(shí)來到T2時(shí)間片,線程A繼續(xù)向前推進(jìn),線程B和C則被按下暫停鍵。

T3時(shí)間片,然而就在線程A拿到鎖運(yùn)行時(shí)因?yàn)槟承┰蛳窀邇?yōu)先級線程槍占之類導(dǎo)致操作系統(tǒng)也剝奪了線程A繼續(xù)持有CPU的權(quán)利,糟糕的是,因?yàn)榫€程A此時(shí)持有鎖,而線程A又無法繼續(xù)向前推進(jìn),這就進(jìn)一步使得線程B和C也無法繼續(xù)向前推進(jìn)。

你會發(fā)現(xiàn)在T3時(shí)刻,這幾個(gè)線程都沒有任何進(jìn)展,根本原因在于我們?yōu)榻鉀Q多線程問題加互斥鎖驚動(dòng)了操作系統(tǒng),而這類互斥鎖是操作系統(tǒng)給我們實(shí)現(xiàn)的,那么解決線程安全問題一定要經(jīng)過操作系統(tǒng)嗎?

不是的,在硬件層面也可以解決線程安全問題,硬件層面當(dāng)然是指CPU,或者說機(jī)器指令。

CPU中有特定的原子指令,實(shí)際上操作系統(tǒng)也是基于這些指令實(shí)現(xiàn)的互斥鎖,既然操作系統(tǒng)能用這些指令,我們(用戶態(tài))也可以使用這些指令,基于此我們可以將上述代碼進(jìn)行簡單改造:

int count = 0;void add() {    int old_value;
do { old_value = count; } while (!atomic_compare_exchange(&count, &old_value, old_value + 1));}

此時(shí)add函數(shù)是線程安全的,我們也沒有對其進(jìn)行加鎖,不管多少線程同時(shí)調(diào)用add函數(shù)得到count都是正確的, 而該函數(shù)的執(zhí)行完全不涉及操作系統(tǒng) ,不需要操作系統(tǒng)來維護(hù)秩序,利用的就是CPU中的原子指令,CPU在硬件層面一樣可以替我們維護(hù)秩序。

上述代碼就是所謂lock-free的, 不管操作系統(tǒng)怎樣調(diào)度這三個(gè)線程,我們都能確保這三個(gè)線程中總有一個(gè)能繼續(xù)向前推進(jìn)

lock-free的系統(tǒng)看起來像這樣:

圖片

對于這類系統(tǒng) 不存在某個(gè)時(shí)間片下線程都無法推進(jìn)的情況 ,換句話說就是lock-free程序保證至少有一個(gè)線程能繼續(xù)向前推進(jìn)。

可以看到,lock-free給出了比普通鎖更優(yōu)的保障。

但不能簡單從代碼是不是加鎖或不加鎖去判斷代碼是否lock-free ,回旋鎖也是沒有上述互斥鎖的,也不經(jīng)過操作系統(tǒng),但回旋鎖并不是lock-free的,如果你這樣利用CPU中的原子操作修改add函數(shù):

int count = 0;int lock = 0;  // 回旋鎖
void add () { int expected = 0; while(!atomic_compare_exchange_weak(&lock, &expected, 1)) expected = 0; count++; lock = 0;}

這就是典型的回旋鎖,然而如果某個(gè)線程持有回旋鎖后被操作系統(tǒng)掛起那么其它線程開始無效的執(zhí)行死循環(huán),除了白白消耗CPU之外它們都無法繼續(xù)向前推進(jìn),顯而易見,如果此時(shí)系統(tǒng)負(fù)載較高那么此類程序的性能會變差。

既然現(xiàn)在你已經(jīng)知道了lock-free我們再繼續(xù)優(yōu)化這段代碼:

std::atomic<int> count;
void add() { ++count;}

這段代碼沒有鎖,也不需要用循環(huán)不斷檢測是否有其它線程修改count,不管操作系統(tǒng)如何調(diào)度這三個(gè)線程, 它們都能在有限的操作數(shù)內(nèi)執(zhí)行完成 ,此時(shí)我們說該程序是wati-free的,wait-free系統(tǒng)運(yùn)行起來像這樣:

圖片

可以看到在任意時(shí)間片內(nèi), 不管操作系統(tǒng)怎樣調(diào)度,所有線程都能向前推進(jìn) 。

wait-free比lock-free的要求更高更加嚴(yán)格,由于wait-free的程序總是能在有限的步驟內(nèi)執(zhí)行完成,因此實(shí)時(shí)性是最好的,適用于那些對實(shí)時(shí)性要求較高的場景,當(dāng)然實(shí)現(xiàn)難度也要比lock-free更高。

值得注意的是,wait-free以及l(fā)ock-free程序的實(shí)現(xiàn)通常不是那么簡單。

好啦,今天就到這里,希望這篇對大家理解多線程有所幫助

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10885

    瀏覽量

    212322
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7091

    瀏覽量

    89256
  • 多線程
    +關(guān)注

    關(guān)注

    0

    文章

    278

    瀏覽量

    20029
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4338

    瀏覽量

    62787
收藏 人收藏

    評論

    相關(guān)推薦

    ESP32會不會有多線程問題,需要加鎖嗎?

    ESP32會不會有多線程問題,需要加鎖
    發(fā)表于 07-19 08:05

    在不改變內(nèi)部程序的情況下,只想改變外部元件,如晶振等,怎樣才能讓實(shí)時(shí)時(shí)鐘加快,

    在不改變內(nèi)部程序的情況下,只想改變外部元件,如晶振等,怎樣才能讓實(shí)時(shí)時(shí)鐘加快,如用1秒的時(shí)間跳30秒?
    發(fā)表于 05-16 17:55

    labview問題怎樣才能在注冊時(shí)信息沒填完整時(shí)注冊,

    用簇制作了一個(gè)注冊頁面包括密碼,,電話,,姓名,,郵箱等,,但是怎樣才能在注冊時(shí)信息沒填完整時(shí)注冊,,提醒信息未填寫完整,,請?zhí)顚懲暾?。?/div>
    發(fā)表于 07-24 16:04

    Linux多線程機(jī)制

    1 線程不能獨(dú)立運(yùn)行,要依附于進(jìn)程2 如果創(chuàng)建一個(gè)子線程只需要重新分配??臻g3 多個(gè)線程可以并行運(yùn)行4 線程之間可以有共同的全局變量(全局區(qū),任何
    發(fā)表于 11-11 09:53

    怎樣才能在SDCARD中運(yùn)行Android系統(tǒng)呢

    怎樣才能在SDCARD中運(yùn)行Android系統(tǒng)呢?怎樣使用rknand.ko在Android上MBR中定義的mount分區(qū)?
    發(fā)表于 02-18 06:43

    在MCU開發(fā)中使用多線程操作一寫一讀是否需要保護(hù)?

    ,那么多線程訪問是安全的,那么對于一寫一讀,在某些情況下需要保護(hù),某些情況下其實(shí)可以不需要保護(hù)。當(dāng)操作數(shù)據(jù)是 1字節(jié) uint8_t 類型數(shù)據(jù),可以不做保護(hù),對于uint8_t類型的數(shù)據(jù),最終轉(zhuǎn)化為匯編
    發(fā)表于 02-01 15:42

    怎樣才能使本本達(dá)到最優(yōu)性能

    怎樣才能使本本達(dá)到最優(yōu)性能 問題:我是一個(gè)最近購本的菜鳥,請問怎樣才能使本本達(dá)到最優(yōu)的性能? 回
    發(fā)表于 01-25 14:39 ?526次閱讀

    MFC多線程編程

    計(jì)算機(jī)上的上位機(jī)制作工具語言之MFC多線程編程
    發(fā)表于 09-01 14:55 ?0次下載

    Linux多線程編程

    線程呢?使用多線程到底有哪些好處?什么的系統(tǒng)應(yīng)該選用多線程?我們首先必須回答這些問題?! ∈褂?b class='flag-5'>多線程的理由之一是和進(jìn)程相比,它是一種非常"節(jié)儉"的多任務(wù)操作方式。我們知道,在Linux
    發(fā)表于 04-02 14:43 ?618次閱讀

    在哪幾種情況下會造成伺服電機(jī)抖動(dòng)

    在哪幾種情況下會造成伺服電機(jī)抖動(dòng)?怎樣才能解決這些伺服電機(jī)抖動(dòng)帶來的問題?分別是怎么解決的?
    的頭像 發(fā)表于 02-22 16:14 ?2024次閱讀

    在哪幾種情況下會造成伺服電機(jī)抖動(dòng)?

    在哪幾種情況下會造成伺服電機(jī)抖動(dòng)?怎樣才能解決這些伺服電機(jī)抖動(dòng)帶來的問題?分別是怎么解決的?
    發(fā)表于 05-24 09:41 ?403次閱讀

    多線程情況下如何對一個(gè)值進(jìn)行 a++ 操作

    多線程情況下,對一個(gè)值進(jìn)行 a++ 操作,會出現(xiàn)什么問題? a++ 的問題 先寫個(gè) demo 的例子。把 a++ 放入多線程中運(yùn)行一。定義 10 個(gè)
    的頭像 發(fā)表于 10-13 11:17 ?733次閱讀
    在<b class='flag-5'>多線程</b>的<b class='flag-5'>情況下</b>如何對一個(gè)值進(jìn)行 a++ 操作

    什么情況下避免使用系統(tǒng)調(diào)用

    制。如果對變量的每次訪問都使用上述機(jī)制,由于系統(tǒng)調(diào)用會陷入內(nèi)核空間,需要頻繁的進(jìn)行上下文切換,這就導(dǎo)致了程序的時(shí)間開銷比較大。 自然的,我們就想到,在多線程環(huán)境中,在某些情況下是否能減少甚至避免使用系統(tǒng)調(diào)用?答案是肯
    的頭像 發(fā)表于 11-13 10:32 ?470次閱讀
    什么<b class='flag-5'>情況下</b>避免使用系統(tǒng)調(diào)用

    怎樣才能在有限的容量下發(fā)揮電池的極限續(xù)航能力

    電子發(fā)燒友網(wǎng)站提供《怎樣才能在有限的容量下發(fā)揮電池的極限續(xù)航能力.doc》資料免費(fèi)下載
    發(fā)表于 11-14 14:38 ?0次下載
    <b class='flag-5'>怎樣才能在</b>有限的容量下發(fā)揮電池的極限續(xù)航能力

    多線程同步的幾種方法

    多線程同步是指在多個(gè)線程并發(fā)執(zhí)行的情況下,為了保證線程執(zhí)行的正確性和一致性,需要采用特定的方法來協(xié)調(diào)線程之間的執(zhí)行順序和共享資源的訪問。下面
    的頭像 發(fā)表于 11-17 14:16 ?1212次閱讀
    主站蜘蛛池模板: 色久天| 色婷婷国产麻豆AV | 午夜宅宅伦电影网| 老头xxx| 久久深夜视频| 精品网站一区二区三区网站| 国产精品免费久久久久影院| 日久精品不卡一区二区| 男男高h浪荡受h| 毛片网站网址| 蜜桃臀无码内射一区二区三区| 宝贝乖女好紧好深好爽老师| 在线 日韩 欧美 国产 社区| 亚洲国产系列一区二区三区| 妙玉被肉干高H潮文| 美女被日出水| 蜜桃日本免费观看MV| 妺妺窝人体色777777野大粗| 老师洗澡让我吃她胸的视频| 久久久久久久久女黄9999| 久久精品视在线观看85| 久久久青青| 美女扒开腿让男生桶爽免费APP| 国产三级多多影院| 国产欧美一区二区精品性色tv| a一级一片免费观看视频| 18video性欧美19sex高清| 18动漫在线观看| 99热国产这里只有精品9九| 亚洲精品无码葡京AV天堂| 亚洲 日本 欧美 中文字幕| 青青青草免费| 漂亮的保姆6在线观看中文 | 爱看吧孕妇网| 扒开屁股眼往里面夹东西| 成 人 色综合| 国产精品99久久久精品无码| 99热在线视频| 出差无套内射小秘书| 国产传媒麻豆剧精品AV| 国产在线精彩亚洲久久|