Let’s first look at the problem with this piece of code:
var wg var x int64 func main() { (2) go f() go f() () (x) // Output: 12135} func f() { for i:=0;i<10000;i++ { x = x+1 } () }
Why is the output here 12135 (different machines have different results), not 20000.
Because the assignment of x is divided into three steps: taking out the value of x, calculating the result of x, and assigning the value to x. So since the goroutine coroutine is used for the call to the f function, there is a problem of resource competition, so there is dirty data during the assignment and calculation process. For such problems, mutex locks can be used:
Mutex lock
Mutex is a commonly used method to control access to shared resources. It can ensure that only one goroutine can access shared resources at the same time. The Mutex type of the sync package is used in Go language to implement mutex locks.
var wg var x int64 var lock func main() { (2) go f() go f() () (x) // Output: 20000} func f() { for i:=0;i<10000;i++ { () // Add mutex lock x = x+1 () // Unlock } () }
Using a mutex can ensure that there is only one goroutine at the same time and only one goroutine enters the critical area, while other goroutines are waiting for the lock; when the mutex is released, the waiting goroutine can acquire the lock and enter the critical area. When multiple goroutines are waiting for a lock at the same time, the awakening strategy is random.
Read and write mutex lock
Mutex locks are completely mutually exclusive, but in many practical scenarios, there are more reads, fewer writes, and there is no need to add locks when we read a resource concurrently without involving resource modification. In this scenario, using reads, writes, locks are a better choice. Read and write locks use the RWMutex type in the sync package in Go language.
Read and write locks are divided into two types: read and write locks. When a goroutine acquires the read lock, other goroutines will continue to acquire the lock if they acquire the read lock, and if they acquire the write lock, they will wait; when a goroutine acquires the write lock, other goroutines will wait whether they acquire the read lock or the write lock.
var ( x1 int64 wg1 lock1 rwlock ) func main() { startTime := () for i:=0;i<100;i++ { (1) write() } for i:=0;i<10000;i++ { (1) read() } () (().Sub(startTime)) // Time to use mutex: 973.9304ms // Time to read and write mutex: 718.094ms} func read() { defer () //() // Mutex lock () // Read and write mutex lock (x1) //() // Mutex lock () // Read and write mutex lock} func write() { defer () () x1 = x1+1 () }
This is the end of this article about the implementation of Go mutexes and read-write mutexes. For more related contents of Go mutexes and read-write mutexes, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!