欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go中sync.Mutex 加鎖失效的問題解決

 更新時間:2024年08月20日 10:22:51   作者:Looooking  
sync.Mutex是Go標準庫中常用的一個排外鎖,本文主要介紹了Go中sync.Mutex 加鎖失效的問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

我先聲明一下,并不是真的加鎖失效,而是我之前的理解有誤,導致看起來像是加鎖失效一樣。于是乎記錄一下,加深一下印象。

我之前有個理解誤區(qū)(不知道大家有沒有,有的話趕緊糾正一下——其實也是因為我這塊的知識掌握不牢固導致的):覺得只要是加鎖后,在我主動調用解鎖之前,這個塊范圍內的變量一定不會被其他地方修改。后來驗證發(fā)現(xiàn),我大錯特錯了。

起因

最近在學習 sync.Mutex 加鎖時,寫了下面一段代碼進行練習。

package main

import (
	"fmt"
	"sync"
	"time"
)


type Info struct {
	mu sync.Mutex
	Value string
}

func Update(info *Info) {
	fmt.Printf("%s: before update. Value: %s\n", time.Now().Format(timeFormat), info.Value)
	info.mu.Lock()
	defer info.mu.Unlock()
	time.Sleep(2 * time.Second)
	fmt.Printf("%s: in update. Value: %s\n", time.Now().Format(timeFormat), info.Value)
	info.Value = "update"
	fmt.Printf("%s: after update. Value: %s\n", time.Now().Format(timeFormat), info.Value)
}

const timeFormat = "2006-01-02 15:04:05"

func main() {
	fmt.Printf("%s: main start\n", time.Now().Format(timeFormat))
	info := &Info{}
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		Update(info)
	}()
	time.Sleep(time.Second)
	info.Value = "main"
	fmt.Printf("%s: in main. Value: %s\n", time.Now().Format(timeFormat), info.Value)
	wg.Wait()
}

按照我原先上面的理解,Update() 函數(shù)當中,before update 和 in update 中對應結構體的值應該是不會變的(畢竟我加了鎖)。然而從運行結果發(fā)現(xiàn),Update() 函數(shù)執(zhí)行期間,結構體變量的 Value 竟然還是被外部主線程修改了。

分析

那么為什么會這樣呢?明明 Update() 里邊已經(jīng)添加了鎖,為什么執(zhí)行期間還是會被其他地方修改呢?

最后發(fā)現(xiàn),究其原因,還是在于主線程修改變量的值的時候,沒有先判斷鎖 mu 是否已經(jīng)釋放,就直接進行了修改操作。

主線程中加上獲取鎖的操作后,會先判斷當前鎖是否被釋放,如果沒被釋放,就會一直進行等待直到鎖釋放后才繼續(xù)執(zhí)行后面的操作。

輸出結果也和預期保持一致 。

2024-04-16 23:59:13: main start
2024-04-16 23:59:13: before update. Value: 
2024-04-16 23:59:15: in update. Value: 
2024-04-16 23:59:15: after update. Value: update
2024-04-16 23:59:15: in main. Value: main

正常來說,鎖是要配合多 goroutine 來使用的, 對于單線程來說,由于沒有其他線程進行資源競爭,加鎖的意義不大;對于多 goroutine 而言,對于獲取和釋放鎖的時機,應該由應用程序合理控制。關于鎖的使用,還有一些其他注意事項,這塊也一并寫一下。

  • 在一個 goroutine 獲得 Mutex 后,其他 goroutine 只能等到這個 goroutine 釋放該 Mutex
  • 使用 Lock() 加鎖后,不能再繼續(xù)對其加鎖,直到利用 Unlock() 解鎖后才能再加鎖
  • 在 Lock() 之前使用 Unlock() 會導致 panic 異常
  • 已經(jīng)鎖定的 Mutex 并不與特定的 goroutine 相關聯(lián),這樣可以利用一個 goroutine 對其加鎖,再利用其他 goroutine 對其解鎖
  • 在同一個 goroutine 中的 Mutex 解鎖之前再次進行加鎖,會導致死鎖
  • 適用于讀寫不確定,并且只有一個讀或者寫的場景

緩沖通道實現(xiàn)互斥邏輯

當然,我們還可以通過緩沖為1的通道實現(xiàn)互斥鎖的邏輯。

package main

import (
	"fmt"
	"sync"
	"time"
)


type Info struct {
	Value string
}

func Update(info *Info, sem chan bool) {
	fmt.Printf("%s: before update. Value: %s\n", time.Now().Format(timeFormat), info.Value)
	sem <- true
	defer func() {
		<- sem
	}()
	time.Sleep(2 * time.Second)
	fmt.Printf("%s: in update. Value: %s\n", time.Now().Format(timeFormat), info.Value)
	info.Value = "update"
	fmt.Printf("%s: after update. Value: %s\n", time.Now().Format(timeFormat), info.Value)
}

const timeFormat = "2006-01-02 15:04:05"

func main() {
	sem := make(chan bool, 1)
	fmt.Printf("%s: main start\n", time.Now().Format(timeFormat))
	info := &Info{}
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		Update(info, sem)
	}()
	time.Sleep(time.Second)
	sem <- true
	info.Value = "main"
	fmt.Printf("%s: in main. Value: %s\n", time.Now().Format(timeFormat), info.Value)
	<- sem
	wg.Wait()
}

2024-04-17 00:26:25: main start
2024-04-17 00:26:25: before update. Value: 
2024-04-17 00:26:26: in main. Value: main
2024-04-17 00:26:27: in update. Value: main
2024-04-17 00:26:27: after update. Value: update

到此這篇關于Go中sync.Mutex 加鎖失效的問題解決的文章就介紹到這了,更多相關Go sync.Mutex 加鎖失效內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家! 

相關文章

  • Golang限流庫與漏桶和令牌桶的使用介紹

    Golang限流庫與漏桶和令牌桶的使用介紹

    這篇文章主要介紹了golang限流庫以及漏桶與令牌桶的實現(xiàn)原理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧
    2023-03-03
  • 使用Go語言編寫簡潔代碼的最佳實踐

    使用Go語言編寫簡潔代碼的最佳實踐

    簡潔的代碼對于創(chuàng)建可維護、可閱讀和高效的軟件至關重要,Go 是一種強調簡單和代碼整潔的語言,在本文中,我們將結合代碼示例,探討編寫簡潔 Go 代碼的最佳實踐,需要的朋友可以參考下
    2023-09-09
  • golang與pgsql交互的實現(xiàn)

    golang與pgsql交互的實現(xiàn)

    本文主要介紹了golang與pgsql交互的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • golang關閉chan通道的方法示例

    golang關閉chan通道的方法示例

    在go語言中,通道(channel)是一個非常重要的概念,通道提供了一種在不同 goroutine 之間安全地傳遞數(shù)據(jù)的方式,在本文中,我們將討論如何關閉通道以及在關閉通道時需要考慮的事項,需要的朋友可以參考下
    2024-02-02
  • golang復用http.request.body的方法示例

    golang復用http.request.body的方法示例

    這篇文章主要給大家介紹了關于golang復用http.request.body的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-10-10
  • Go?實現(xiàn)?Nginx?加權輪詢算法的方法步驟

    Go?實現(xiàn)?Nginx?加權輪詢算法的方法步驟

    本文主要介紹了Go?實現(xiàn)?Nginx?加權輪詢算法的方法步驟,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • go語言結構體指針操作示例詳解

    go語言結構體指針操作示例詳解

    這篇文章主要為大家介紹了go語言結構體指針操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • Golang使用panic控制程序錯誤流程

    Golang使用panic控制程序錯誤流程

    這篇文章主要介紹了Golang使用panic控制程序錯誤流程,Golang panic異常處理機制中的一種流程控制方式,用于中斷程序流程并觸發(fā)異常處理
    2023-04-04
  • Golang如何快速刪除map所有元素

    Golang如何快速刪除map所有元素

    這篇文章主要介紹了Golang如何快速刪除map所有元素問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Golang實現(xiàn)自己的Redis(有序集合跳表)實例探究

    Golang實現(xiàn)自己的Redis(有序集合跳表)實例探究

    這篇文章主要為大家介紹了Golang實現(xiàn)自己的Redis(有序集合跳表)實例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01

最新評論