📜  Golang 中的互斥锁实例

📅  最后修改于: 2021-10-24 12:59:24             🧑  作者: Mango

Mutex 是一种用作锁定机制的方法,以确保在任何时间点只有一个 Goroutine 访问代码的临界区。这样做是为了防止发生竞争条件。同步包包含互斥锁。 Mutex 上定义的两个方法

  • 开锁

调用 Lock 和 Unlock 之间的任何代码都将仅由一个 Goroutine 执行。

mutex.Lock() 

x = x + 1 // this statement be executed
          // by only one Goroutine 
          // at any point of time  

mutex.Unlock()

如果一个 Goroutine 已经拥有锁,并且如果一个新的 Goroutine 试图获取锁,那么新的 Goroutine 将被停止,直到互斥锁被解锁。要理解这个概念,让我们首先了解一个具有竞争条件的程序。

具有竞争条件的程序

这是一个遇到竞争条件的程序示例

// Program with race condition
package main  
import (  
    "fmt"
    "sync" // to import sync later on
)
var GFG  = 0
  
// This is the function we’ll run in every
// goroutine. Note that a WaitGroup must
// be passed to functions by pointer.  
func worker(wg *sync.WaitGroup) {  
    GFG = GFG + 1
  
    // On return, notify the 
    // WaitGroup that we’re done.
    wg.Done()
}
func main() { 
  
    // This WaitGroup is used to wait for 
    // all the goroutines launched here to finish. 
    var w sync.WaitGroup
  
    // Launch several goroutines and increment
    // the WaitGroup counter for each
    for i := 0; i < 1000; i++ {
        w.Add(1)        
        go worker(&w)
    }
    // Block until the WaitGroup counter
    // goes back to 0; all the workers 
    // notified they’re done.
    w.Wait()
    fmt.Println("Value of x", GFG)
}

说明:在上面的程序中,第 1 行的worker函数。 12 将GFG的值增加 1,然后在WaitGroup上调用Done()以通知其完成。工作函数被调用 1000 次。这些 Goroutines 中的每一个都同时运行,并且在尝试增加第 1 行的GFG时会发生竞争条件。 13 因为多个 Goroutine 尝试同时访问GFG的值。由于竞争条件,多次运行相同的程序每次都会给出不同的输出。

使用互斥体解决上述问题

这是一个如何修复竞争条件的程序示例。

// Program with race condition fixed by mutex
package main  
import (  
    "fmt"
    "sync" // to import sync later on
)
var GFG  = 0
  
// This is the function we’ll run in every
// goroutine. Note that a WaitGroup must
// be passed to functions by pointer.  
func worker(wg *sync.WaitGroup, m *sync.Mutex) { 
    // Lock() the mutex to ensure 
    // exclusive access to the state, 
    // increment the value,
    // Unlock() the mutex
    m.Lock() 
    GFG = GFG + 1
    m.Unlock()
  
    // On return, notify the 
    // WaitGroup that we’re done.
    wg.Done()
}
func main() { 
    // This WaitGroup is used to wait for 
    // all the goroutines launched here to finish. 
    var w sync.WaitGroup
  
    // This mutex will synchronize access to state.
    var m sync.Mutex
  
    // Launch several goroutines and increment
    // the WaitGroup counter for each
    for i := 0; i < 1000; i++ {
        w.Add(1)        
        go worker(&w, &m)
    }
    // Block until the WaitGroup counter
    // goes back to 0; all the workers 
    // notified they’re done.
    w.Wait()
    fmt.Println("Value of x", GFG)
}

输出:
x 1000 的值

说明:互斥为结构类型和互斥在管线创建任何类型的变量m。 31. 更改了工作函数,以便在第 1 行中增加GFG的代码。 18 在m.Lock()m.Unlock() 之间。现在在任何时间点都只允许一个 Goroutine 执行这段代码,从而处理竞争条件。

互斥锁的地址必须在行号中传递。 37. 如果互斥量是按值传递的,那么每个 Goroutine 将拥有自己的互斥量副本,并且竞争条件仍然存在。