3 回答

TA貢獻(xiàn)1829條經(jīng)驗 獲得超7個贊
根據(jù)Go內(nèi)存模型:
不能保證一個 goroutine 會看到另一個 goroutine 執(zhí)行的操作,除非兩者之間使用通道互斥體進(jìn)行顯式同步。等。
在你的例子中:一個 goroutines 看到的事實并不意味著它會看到 set。僅當(dāng) goroutines 之間存在顯式同步時,才能保證這一點。done=true
a
可能提供這樣的同步,所以這就是為什么你沒有觀察到這種行為。仍然有一場內(nèi)存競賽,在不同的平臺上,有不同的實現(xiàn),事情可能會發(fā)生變化。sync.Once
sync.Once

TA貢獻(xiàn)1775條經(jīng)驗 獲得超11個贊
有關(guān) Go Memory 模型的參考頁面會告訴您以下內(nèi)容:
編譯器和處理器可以對在單個 goroutine 中執(zhí)行的讀取和寫入進(jìn)行重新排序,前提是重新排序不會更改語言規(guī)范所定義的 goroutine 中的行為。
因此,編譯器可以在函數(shù)體內(nèi)對兩次寫入重新排序,從setup
a = "hello, world"
done = true
自
done = true
a = "hello, world"
然后可能會出現(xiàn)以下情況:
一個 goroutine 不觀察寫入,因此啟動函數(shù)的單次執(zhí)行;doprintdonesetup
另一個 goroutine 觀察寫入 ,但在觀察寫入之前完成執(zhí)行 ;因此,它打印 類型的零值,即空字符串。doPrintdoneaa
我運行了大約五次這段代碼,每次都打印了“hello world”。
您需要了解同步錯誤(代碼的屬性)和爭用條件(特定執(zhí)行的屬性)之間的區(qū)別;Valentin Deleplace的這篇文章在闡明這種區(qū)別方面做得很好。簡而言之,同步錯誤可能會也可能不會引起爭用條件;但是,僅僅因為爭用條件不會在程序的多次執(zhí)行中表現(xiàn)出來,并不意味著您的程序沒有錯誤。
在這里,您可以“強制”爭用條件發(fā)生,只需對兩個寫入進(jìn)行重新排序并在兩者之間添加一個微小的睡眠即可。setup
func setup() {
done = true
time.Sleep(1 * time.Millisecond)
a = "hello, world"
}
這可能足以說服您該程序確實包含同步錯誤。

TA貢獻(xiàn)1798條經(jīng)驗 獲得超3個贊
該程序不是內(nèi)存安全的,因為:
多個 goroutine 同時訪問同一內(nèi)存 ( 和 )。
done
a
并發(fā)訪問并不總是由顯式同步控制。
訪問可以寫入/修改內(nèi)存。
試圖推理程序在這些變量方面將如何表現(xiàn)或不將如何表現(xiàn)可能只是不必要的混淆,因為它實際上是未定義的行為。沒有“正確”的答案。只有間接觀察,它們不能硬保證它們是否或何時成立。
- 3 回答
- 0 關(guān)注
- 151 瀏覽
添加回答
舉報