【Golang】競態(tài)條件 (Race Conditions)

歡迎關(guān)注微信公眾號:全棧工廠

1. 什么是競態(tài)條件?

競態(tài)條件是指在并發(fā)環(huán)境中,當(dāng)有多個事件同時訪問同一個臨界資源時,由于多個事件的并發(fā)執(zhí)行順序的不確定,從而導(dǎo)致程序輸出結(jié)果的不確定,這種情況我們稱之為競態(tài)條件 (Race Conditions)或者競爭冒險(race hazard)。
在golang的多協(xié)程環(huán)境中比較容易出現(xiàn)競態(tài)條件,例如以下代碼:

package main

import (
    "sync"
)

var wg sync.WaitGroup
var Total = 0

func main() {
    for concurrence := 0; concurrence < 1000; concurrence++ {
        wg.Add(1)
        go goroutine()
    }
    wg.Wait()
    println("Total:", Total)
}

func goroutine() {
    Total++
    wg.Done()
}

上述代碼,我們執(zhí)行了5次,沒吃執(zhí)行結(jié)果都不一樣:


其最主要的原因就是由于多協(xié)程同時訪問臨界變量Total,從而出現(xiàn)臟讀,導(dǎo)致1000個協(xié)程的累加和最終小于1000

2. 怎么發(fā)現(xiàn)競態(tài)條件?

在golang 1.1版本中,引入了競態(tài)條件檢測工具(race detector),只要帶編譯執(zhí)行時加入 -race 參數(shù)即可:

go build -race main.go
或:
go run -race main.go

用上述命令執(zhí)行程序,我們會發(fā)現(xiàn):


執(zhí)行結(jié)果警告第20行出現(xiàn)竟態(tài)條件,這樣我們就能快速定位問題代碼。

3. 如何修復(fù)竟態(tài)條件?

給臨界代碼去添加互斥鎖可以很好的解決競態(tài)條件問題,例如:

package main

import (
    "sync"
)

var wg  sync.WaitGroup
var Total = 0
var mu sync.Mutex

func main() {
    for concurrence := 0; concurrence < 1000; concurrence++ {
        wg.Add(1)
        go goroutine(&wg)
    }
    wg.Wait()
    println("Total:", Total)
}

func goroutine(wg *sync.WaitGroup) {
    mu.Lock()
    Total++
    mu.Unlock()
    wg.Done()
}

我們對全局變量Total的讀寫添加了互斥鎖,這樣我們再執(zhí)行的時候就不再報竟態(tài)條件警告了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容