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 { |