併發技術4:讀寫鎖

尹成發表於2018-11-16

讀寫鎖概述

  • 除了上一篇提到的互斥鎖以外,Go語言還給我們提供了另一種資源鎖——讀寫鎖(sync.RWMutex);
  • 讀寫鎖可以鎖定和解鎖兩種模式:只讀模式和只寫模式:
  • 只讀模式:多路只讀不可寫;
  • 只寫模式:單路只寫不可讀;

只讀模式示例

//定義讀寫鎖
var rwMutex sync.RWMutex

/*只讀模式:多路只讀不可寫*/
func main() {
	for i := 0; i < 3; i++ {
		go read(i)
	}
	time.Sleep(500 * time.Millisecond)
	for i := 0; i < 3; i++ {
		go write(i)
	}
	time.Sleep(10*time.Second)
}

func read(i int) {
	rwMutex.RLock()
	fmt.Println(i, "reading...")
	time.Sleep(time.Second)
	fmt.Println(i, "read over")
	rwMutex.RUnlock()
}

func write(i int) {
	rwMutex.Lock()
	fmt.Println(i, "writing...")
	time.Sleep(time.Second)
	fmt.Println(i, "write over")
	rwMutex.Unlock()
}

其輸出效果為:
1 reading…
2 reading…
0 reading…
0 read over
2 read over
1 read over
2 writing…
2 write over
0 writing…
0 write over
1 writing…
1 write over

不難看出,在只讀模式下,三條協程同時在進行讀取;而只有全部讀取協程結束並釋放只讀鎖後,寫模式才得以執行——此之謂“多路只讀不可寫”

只寫模式示例

//定義讀寫鎖
var rwMutex sync.RWMutex

/*只寫模式:單路只寫不可讀*/
func main() {
	for i := 0; i < 3; i++ {
		go write(i)
	}
	time.Sleep(500 * time.Millisecond)
	for i := 0; i < 3; i++ {
		go read(i)
	}

	time.Sleep(10*time.Second)
}

func read(i int) {
	rwMutex.RLock()
	fmt.Println(i, "reading...")
	time.Sleep(time.Second)
	fmt.Println(i, "read over")
	rwMutex.RUnlock()
}

func write(i int) {
	rwMutex.Lock()
	fmt.Println(i, "writing...")
	time.Sleep(time.Second)
	fmt.Println(i, "write over")
	rwMutex.Unlock()
}

其輸出為:
1 writing…
1 write over
0 reading…
1 reading…
2 reading…
2 read over
0 read over
1 read over
2 writing…
2 write over
0 writing…
0 write over

不難看出,在只寫鎖釋放之前,只有一條協程可以執行寫操作,其餘協程無論讀寫都被阻塞——此之謂“單路只寫不可讀”;
當只寫鎖釋放時,首先被只讀鎖搶到資源,又是一個三路齊讀沒有寫;
最後再次鎖定為只寫時,也是逐條寫入直到釋放只寫鎖,其間其餘的寫協程全部被阻塞;

學院Go語言視訊主頁
https://edu.csdn.net/lecturer/1928

清華團隊帶你實戰區塊鏈開發
掃碼獲取海量視訊及原始碼 QQ群:721929980
在這裡插入圖片描述

相關文章