最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言并發(fā)編程 互斥鎖詳情

 更新時間:2021年10月20日 15:52:04   作者:測試開發(fā)小記  
在并發(fā)編程中,多個Goroutine訪問同一塊內(nèi)存資源時可能會出現(xiàn)競態(tài)條件,我們需要在臨界區(qū)中使用適當?shù)耐讲僮鱽硪员苊飧倯B(tài)條件。Go 語言中提供了很多同步工具,本文將介紹互斥鎖Mutex和讀寫鎖RWMutex的使用方法。

1、互斥鎖Mutex

1.1 Mutex介紹

Go 語言的同步工具主要由 sync 包提供,互斥鎖 (Mutex) 與讀寫鎖 (RWMutex) 就是sync 包中的方法。

互斥鎖可以用來保護一個臨界區(qū),保證同一時刻只有一個 goroutine 處于該臨界區(qū)內(nèi)。主要包括鎖定(Lock方法)和解鎖(Unlock方法)兩個操作,首先對進入臨界區(qū)的goroutine進行鎖定,離開時進行解鎖。

使用互斥鎖 (Mutex)時要注意以下幾點:

  • 不要重復(fù)鎖定互斥鎖,否則會阻塞,也可能會導致死鎖(deadlock);
  • 要對互斥鎖進行解鎖,這也是為了避免重復(fù)鎖定;
  • 不要對未鎖定或者已解鎖的互斥鎖解鎖;
  • 不要在多個函數(shù)之間直接傳遞互斥鎖,sync.Mutex類型屬于值類型,將它傳給一個函數(shù)時,會產(chǎn)生一個副本,在函數(shù)中對鎖的操作不會影響原鎖

總之,一個互斥鎖只用來保護一個臨界區(qū),加鎖后記得解鎖,對于每一個鎖定操作,都要有且只有一個對應(yīng)的解鎖操作,也就是加鎖和解鎖要成對出現(xiàn),最保險的做法時使用defer語句解鎖。

1.2 Mutex使用實例

下面的代碼模擬取錢和存錢操作:

package main

import (
 "flag"
 "fmt"
 "sync"
)

var (
    mutex   sync.Mutex
    balance int
    protecting uint  // 是否加鎖
    sign = make(chan struct{}, 10) //通道,用于等待所有g(shù)oroutine
)

// 存錢
func deposit(value int) {
    defer func() {
        sign <- struct{}{}
    }()

    if protecting == 1 {
        mutex.Lock()
        defer mutex.Unlock()
    }

    fmt.Printf("余額: %d\n", balance)
    balance += value
    fmt.Printf("存 %d 后的余額: %d\n", value, balance)
    fmt.Println()

}

// 取錢
func withdraw(value int) {
    defer func() {
        sign <- struct{}{}
    }()
    
    if protecting == 1 {
        mutex.Lock()
        defer mutex.Unlock()
    }

    fmt.Printf("余額: %d\n", balance)
    balance -= value
    fmt.Printf("取 %d 后的余額: %d\n", value, balance)
    fmt.Println()

}

func main() {
    
    for i:=0; i < 5; i++ {
        go withdraw(500) // 取500
        go deposit(500)  // 存500
    }

    for i := 0; i < 10; i++ {
  <-sign
 }
    fmt.Printf("當前余額: %d\n", balance)
}

func init() {
    balance = 1000 // 初始賬戶余額為1000
    flag.UintVar(&protecting, "protecting", 0, "是否加鎖,0表示不加鎖,1表示加鎖")
}



上面的代碼中,使用了通道來讓主 goroutine 等待其他 goroutine 運行結(jié)束,每個子goroutine在運行結(jié)束之前向通道發(fā)送一個元素,主 goroutine 在最后從這個通道接收元素,接收次數(shù)與子goroutine個數(shù)相同。接收完后就會退出主goroutine。

代碼使用協(xié)程實現(xiàn)多次(5次)對一個賬戶進行存錢和取錢的操作,先來看不加鎖的情況

余額: 1000
存 500 后的余額: 1500

余額: 1000
取 500 后的余額: 1000

余額: 1000
存 500 后的余額: 1500

余額: 1000
取 500 后的余額: 1000

余額: 1000
存 500 后的余額: 1500

余額: 1000
取 500 后的余額: 1000

余額: 1000
取 500 后的余額: 500

余額: 1000
存 500 后的余額: 1000

余額: 1000
取 500 后的余額: 500

余額: 1000
存 500 后的余額: 1000

當前余額: 1000

可以看到出現(xiàn)了混亂,比如第二次1000的余額取500后還是1000,這種對同一資源的競爭出現(xiàn)了競態(tài)條件(Race Condition)。

下面來看加鎖的執(zhí)行結(jié)果:

余額: 1000
取 500 后的余額: 500

余額: 500
存 500 后的余額: 1000

余額: 1000
取 500 后的余額: 500

余額: 500
存 500 后的余額: 1000

余額: 1000
取 500 后的余額: 500

余額: 500
存 500 后的余額: 1000

余額: 1000
存 500 后的余額: 1500

余額: 1500
取 500 后的余額: 1000

余額: 1000
取 500 后的余額: 500

余額: 500
存 500 后的余額: 1000

當前余額: 1000
加鎖后就正常了。

下面介紹更細化的互斥鎖:讀/寫互斥鎖RWMutex

2、讀寫鎖RWMutex

2.1 RWMutex介紹

讀/寫互斥鎖RWMutex包含了讀鎖和寫鎖,分別對共享資源的“讀操作”和“寫操作”進行保護。sync.RWMutex類型中的Lock方法和Unlock方法分別用于對寫鎖進行鎖定和解鎖,而它的RLock方法和RUnlock方法則分別用于對讀鎖進行鎖定和解鎖。

有了互斥鎖Mutex,為什么還需要讀寫鎖呢?因為在很多并發(fā)操作中,并發(fā)讀取占比很大,寫操作相對較少,讀寫鎖可以并發(fā)讀取,這樣可以提供服務(wù)性能。讀寫鎖具有以下特征:

讀寫鎖 讀鎖 寫鎖
讀鎖 Yes No
寫鎖 No No

也就是說:

  • 如果某個共享資源受到讀鎖和寫鎖保護時,其它goroutine不能進行寫操作。換句話說就是讀寫操作和寫寫操作不能并行執(zhí)行,也就是讀寫互斥;
  • 受讀鎖保護時,可以同時進行多個讀操作。

在使用讀寫鎖時,還需要注意:

  • 不要對未鎖定的讀寫鎖解鎖;
  • 對讀鎖不能使用寫鎖解鎖
  • 對寫鎖不能使用讀鎖解鎖

2.2 RWMutex使用實例

改寫前面的取錢和存錢操作,添加查詢余額的方法:

package main

import (
 "fmt"
 "sync"
)

// account 代表計數(shù)器。
type account struct {
 num uint         // 操作次數(shù)
 balance int   // 余額
 rwMu  *sync.RWMutex // 讀寫鎖
}

var sign = make(chan struct{}, 15) //通道,用于等待所有g(shù)oroutine

// 查看余額:使用讀鎖
func (c *account) check() {
 defer func() {
        sign <- struct{}{}
    }()
 c.rwMu.RLock()
 defer c.rwMu.RUnlock()
 fmt.Printf("%d 次操作后的余額: %d\n", c.num, c.balance)
}

// 存錢:寫鎖
func (c *account) deposit(value int) {
 defer func() {
        sign <- struct{}{}
    }()
    c.rwMu.Lock()
 defer c.rwMu.Unlock() 

 fmt.Printf("余額: %d\n", c.balance)   
 c.num += 1
    c.balance += value
    fmt.Printf("存 %d 后的余額: %d\n", value, c.balance)
    fmt.Println() 
}

// 取錢:寫鎖
func (c *account) withdraw(value int) {
    defer func() {
        sign <- struct{}{}
    }()
 c.rwMu.Lock()
 defer c.rwMu.Unlock()   
 fmt.Printf("余額: %d\n", c.balance)     
 c.num += 1
    c.balance -= value
 fmt.Printf("取 %d 后的余額: %d\n", value, c.balance)
    fmt.Println()  
}


func main() {
 c := account{0, 1000, new(sync.RWMutex)}

 for i:=0; i < 5; i++ {
        go c.withdraw(500) // 取500
        go c.deposit(500)  // 存500
  go c.check()
    }

    for i := 0; i < 15; i++ {
  <-sign
 }
 fmt.Printf("%d 次操作后的余額: %d\n", c.num, c.balance)

}

執(zhí)行結(jié)果:

余額: 1000
取 500 后的余額: 500

1 次操作后的余額: 500
1 次操作后的余額: 500
1 次操作后的余額: 500
1 次操作后的余額: 500
1 次操作后的余額: 500
余額: 500
存 500 后的余額: 1000

余額: 1000
取 500 后的余額: 500

余額: 500
存 500 后的余額: 1000

余額: 1000
存 500 后的余額: 1500

余額: 1500
取 500 后的余額: 1000

余額: 1000
取 500 后的余額: 500

余額: 500
存 500 后的余額: 1000

余額: 1000
取 500 后的余額: 500

余額: 500
存 500 后的余額: 1000

10 次操作后的余額: 1000

讀寫鎖和互斥鎖的不同之處在于讀寫鎖把對共享資源的讀操作和寫操作分開了,可以實現(xiàn)更復(fù)雜的訪問控制。

總結(jié):

讀寫鎖也是一種互斥鎖,它是互斥鎖的擴展。在使用時需要注意:

  • 加鎖后一定要解鎖
  • 不要重復(fù)加鎖或者解鎖
  • 不解鎖未鎖定的鎖
  • 不要傳遞互斥鎖

到此這篇關(guān)于Go語言并發(fā)編程 互斥鎖詳情的文章就介紹到這了,更多相關(guān)Go語言并發(fā)編程 互斥鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang一些常用的靜態(tài)檢查工具詳解

    golang一些常用的靜態(tài)檢查工具詳解

    這篇文章主要介紹了golang一些常用的靜態(tài)檢查工具,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Golang操作sqlite3數(shù)據(jù)庫的詳細教程

    Golang操作sqlite3數(shù)據(jù)庫的詳細教程

    最近會使用到sqlite3,這里作個記錄,記性越來越差就是這樣,下面這篇文章主要給大家介紹了關(guān)于Golang操作sqlite3數(shù)據(jù)庫的詳細教程,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-04-04
  • go+redis實現(xiàn)消息隊列發(fā)布與訂閱的詳細過程

    go+redis實現(xiàn)消息隊列發(fā)布與訂閱的詳細過程

    這篇文章主要介紹了go+redis實現(xiàn)消息隊列發(fā)布與訂閱,redis做消息隊列的缺點:沒有持久化,一旦消息沒有人消費,積累到一定程度后就會丟失,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • go語言map與string的相互轉(zhuǎn)換的實現(xiàn)

    go語言map與string的相互轉(zhuǎn)換的實現(xiàn)

    這篇文章主要介紹了go語言map與string的相互轉(zhuǎn)換的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-04-04
  • go?語言爬蟲庫goquery的具體使用

    go?語言爬蟲庫goquery的具體使用

    GoQuery是專為Go語言設(shè)計的一個強大的HTML解析和查詢庫,本文主要介紹了go語言爬蟲庫goquery的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Golang的引用類型和指針的使用與區(qū)別

    Golang的引用類型和指針的使用與區(qū)別

    本文詳細介紹了Golang中的引用類型和指針的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-02-02
  • 一文帶你了解GO語言中方法的應(yīng)用

    一文帶你了解GO語言中方法的應(yīng)用

    GO?語言中的方法實際上和函數(shù)是類似的,只不過在函數(shù)的基礎(chǔ)上多了一個參數(shù),這篇文章主要為大家介紹一下GO語言中方法的應(yīng)用,需要的可以參考下
    2023-09-09
  • 利用go語言編寫一個并發(fā)包

    利用go語言編寫一個并發(fā)包

    這篇文章主要為大家詳細介紹了如何利用go語言編寫一個并發(fā)包,適合大部分并發(fā)任務(wù),開箱即用,文中的示例代碼講解詳細,有需要的小伙伴可以參考下
    2023-10-10
  • 詳解minio分布式文件存儲

    詳解minio分布式文件存儲

    MinIO 是一款基于 Go 語言的高性能、可擴展、云原生支持、操作簡單、開源的分布式對象存儲產(chǎn)品,這篇文章主要介紹了minio分布式文件存儲,需要的朋友可以參考下
    2023-10-10
  • 詳解go中的defer鏈如何被遍歷執(zhí)行

    詳解go中的defer鏈如何被遍歷執(zhí)行

    為了在退出函數(shù)前執(zhí)行一些資源清理的操作,例如關(guān)閉文件、釋放連接、釋放鎖資源等,會在函數(shù)里寫上多個defer語句,多個_defer 結(jié)構(gòu)體形成一個鏈表,G 結(jié)構(gòu)體中某個字段指向此鏈表,那么go中的defer鏈如何被遍歷執(zhí)行,本文將給大家詳細的介紹,感興趣的朋友可以參考下
    2024-01-01

最新評論

温泉县| 宁城县| 仲巴县| 凉城县| 海口市| 湾仔区| 彰武县| 浦县| 望都县| 烟台市| 时尚| 长治市| 兰考县| 平江县| 罗江县| 年辖:市辖区| 罗定市| 张掖市| 南投市| 图木舒克市| 巴南区| 萍乡市| 陈巴尔虎旗| 靖安县| 宝应县| 双江| 大埔区| 申扎县| 区。| 武定县| 临夏县| 大姚县| 伊春市| 康定县| 龙岩市| 西安市| 台山市| 馆陶县| 东海县| 富源县| 新和县|