1 | type Mutex struct {...} |
sync.Mutex 提供了 Lock 和 Unlock 两个方法分别对应上锁和解锁操作,如果锁已经被占据了,Lock 方法会阻塞相应的 goroutine 。在 C 中也有互斥锁的实现,但除了一般的上锁操作和解锁操作,它还多了一种方法 —— pthread_mutex_trylock ,也就是TryLock , pthread_mutex_trylock 语义与 pthread_mutex_lock 类似,不同的是在锁已经被占据时返回 EBUSY 而不是挂起等待。
1 |
|
下面我们自己来实现一个 golang 版本的 try lock 。实现互斥锁的关键就在于原子操作,保证即使有多个 CPU 存在的情况下,也不能同时执行同一条指令。利用 sync/atomic 库下面的方法可以轻松实现对一个数的原子操作。
我们实现的互斥锁中有两个东西,首先是一个 v int32 ,因为是互斥锁,所以初始化为1,还有一个 ch 通道用于唤醒阻塞等待的 goroutine 。
1 | type Mutex struct { |
Lock 方法获取一个锁,如果锁被占据了,则一直阻塞等待( <-m.ch ),等待其他 goroutine 唤醒,相当于 PV 操作中的 P 。
1 | func (m *Mutex) Lock() { |
Unlock 方法释放 Mutex ,如果当前有因为等待该锁而被阻塞的goroutine (说明 atomic.SwapInt32(&m.v, 1) != 0 ),则执行 m.ch <- struct{}{} 将阻塞的 goroutine 唤醒,对应 PV 操作中的 V 。
1 | func (m *Mutex) Unlock() { |
上面的 Lock 方法会在锁可用之前阻塞调用该方法的 goroutine ,TryLoad 方法并不会阻塞,通过 atomic.LoadInt32(&m.v) 来查看当前资源是否可用,如果不可用(说明 v <= 0 ),则返回 false ,如果 atomic.CompareAndSwapInt32(&m.v, 1, 0) 返回 true ,说明资源可用直接上锁。
1 | func (m *Mutex) TryLock() bool { |