Skip to main content
 首页 » 编程设计

Golang互斥锁——读写锁

2022年07月19日156jiqing9006

Golang互斥锁——读写锁

Golang原生支持并发应用,几乎没有其他语言默认支持如此多的并发实现工具。本文在上文的基础上讲解读写锁。

1. 互斥锁解决什么问题

我们并不希望多个线程或协程同时访问相同内存。在并发应用中,很多不同的线程或协程很有可能同时访问相同内存变量。

互斥锁可以实现避免同时读写问题。当一个线程写内存变量,同时另一个线程并发读相同的内存变量。程序将会报错,因为读取线程可能正在读错误数据,这些数据正在发生变化。互斥锁跟踪在任何给定时间哪个线程可以访问一个变量。
在这里插入图片描述

2. 互斥锁示例

请看下面程序:

package main 
 
import ( 
	"fmt" 
) 
 
func main() { 
	m := map[int]int{} 
	go writeLoop(m) 
	go readLoop(m) 
 
	// 阻塞程序,手动结束 
	block := make(chan struct{}) 
	<-block 
} 
 
func writeLoop(m map[int]int) { 
	for { 
		for i := 0; i < 100; i++ { 
			m[i] = i 
		} 
	} 
} 
 
func readLoop(m map[int]int) { 
	for { 
		for k, v := range m { 
			fmt.Println(k, "-", v) 
		} 
	} 
} 
 

程序创建map,然后两个协程同时访问map,一个持续修改map值,同时另一个读取map值并打印。
运行程序,输出如下:

fatal error: concurrent map iteration and map write 

Go认为同时读写map不安全,程序异常结束。

2.1 互斥锁实现

package main 
 
import ( 
	"fmt" 
	"sync" 
) 
 
func main() { 
	m := map[int]int{} 
 
	mux := &sync.Mutex{} 
 
	go writeLoop(m, mux) 
	go readLoop(m, mux) 
 
	// stop program from exiting, must be killed 
	block := make(chan struct{}) 
	<-block 
} 
 
func writeLoop(m map[int]int, mux *sync.Mutex) { 
	for { 
		for i := 0; i < 100; i++ { 
			mux.Lock() 
			m[i] = i 
			mux.Unlock() 
		} 
	} 
} 
 
func readLoop(m map[int]int, mux *sync.Mutex) { 
	for { 
		mux.Lock() 
		for k, v := range m { 
			fmt.Println(k, "-", v) 
		} 
		mux.Unlock() 
	} 
} 

上述代码中增加 sync.Mutex 类型变量 mux。在写循环中,写之前使用Lock()方法加锁,写结束后调用Unlock()方法释放锁。确保没有其他协程在写过程中获得锁,其他协程被阻塞直到写过程结束。

读循环过程中,迭代map之前加锁,结束后释放锁。

2.2 RWMutex ———— 安全实现并发读

Map可以安全地并发访问,但不能并发读/写或写/写。读写锁支持多个读协程同时访问map,但写锁排斥其他协程。

package main 
 
import ( 
	"fmt" 
	"sync" 
) 
 
func main() { 
	m := map[int]int{} 
 
	mux := &sync.RWMutex{} 
 
	go writeLoop(m, mux) 
	go readLoop(m, mux) 
	go readLoop(m, mux) 
	go readLoop(m, mux) 
	go readLoop(m, mux) 
 
	// stop program from exiting, must be killed 
	block := make(chan struct{}) 
	<-block 
} 
 
func writeLoop(m map[int]int, mux *sync.RWMutex) { 
	for { 
		for i := 0; i < 100; i++ { 
			mux.Lock() 
			m[i] = i 
			mux.Unlock() 
		} 
	} 
} 
 
func readLoop(m map[int]int, mux *sync.RWMutex) { 
	for { 
		mux.RLock() 
		for k, v := range m { 
			fmt.Println(k, "-", v) 
		} 
		mux.RUnlock() 
	} 
} 
 

通过使用sync.RWMutex让程序更高效。可以让多个读协程并发访问,同时保证写协程排斥其他协程。

3. 总结

本文通过示例介绍互斥锁,读写互斥锁可以更高效并发读。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/107282509
阅读延展