Skip to content

Latest commit

 

History

History
67 lines (45 loc) · 1.94 KB

method3-1.md

File metadata and controls

67 lines (45 loc) · 1.94 KB

sync.Mutex互斥锁

我们使用一个buffered channel作为一个计数信号量,来保证最多只有20个goroutine会同时执行HTTP请求。 同理,我们可以用一个容量只有1的channel来保证最多只有一个goroutine在同一时刻访问一个共享变量。 一个只能为1和0的信号量叫做二元信号量(binary semaphore)。


var (
    sema    = make(chan struct{}, 1) // a binary semaphore guarding balance
    balance int
)

func Deposit(amount int) {
    sema <- struct{}{} // acquire token”

    balance = balance + amount
    <-sema // release token
}

func Balance() int {
    sema <- struct{}{} // acquire token
    b := balance
    <-sema // release token
    return b
}

这种互斥很实用,而且被sync包里的Mutex类型直接支持。它的Lock方法能够获取到token(这里叫锁),并且Unlock方法会释放这个token:

import "sync"

var (
    mu      sync.Mutex // guards balance
    balance int
)

func Deposit(amount int) {
    mu.Lock()
    balance = balance + amount
    mu.Unlock()
}

func Balance() int {
    mu.Lock()
    b := balance
    mu.Unlock()
    return b
} 

每次一个goroutine访问bank变量时(这里只有balance余额变量),它都会调用mutex的Lock方法来获取一个互斥锁。 如果其它的goroutine已经获得了这个锁的话,这个操作会被阻塞直到其它goroutine调用了Unlock使该锁变回可用状态。 mutex会保护共享变量。惯例来说,被mutex所保护的变量是在mutex变量声明之后立刻声明的。如果你的做法和惯例不符,确保在文档里对你的做法进行说明。

在Lock和Unlock之间的代码段中的内容goroutine可以随便读取或者修改,这个代码段叫做临界区。goroutine在结束后释放锁是必要的,无论以哪条路径通过函数都需要释放,即使是在错误路径中,也要记得释放。 上面的bank程序例证了一种通用的并发模式。