代码实现
package testimport ("fmt""strconv""testing""time"
)type mutexCh struct { //应该大写,给外部所有包用ch chan int // 私有变量,否则外部操作
}func NewMutexCh() *mutexCh {return &mutexCh{ch: make(chan int, 1)}
}func (mc *mutexCh) TryLock() {mc.ch <- 1
}func (mc *mutexCh) TryUnlock() {select {case <-mc.ch:default:panic("unlock an unlocked lock")}
}
func TestChLock(t *testing.T) {mc := NewMutexCh()m := map[int]string{0: "hello",1: "world",}for i := 0; i < 10; i++ {go func(mc *mutexCh, m map[int]string, num int) {mc.TryLock() //阻塞获取锁m[0] = m[0] + strconv.Itoa(i)mc.TryUnlock()}(mc, m, i)}select {default:<-time.After(time.Second)fmt.Println(m)}}
改进点
实际上应该提供Lock方法(阻塞等待),TryLock(如果被占有就返回False)
参考golang实现mutex的源码(内部实际上通过信号量实现)
// Lock locks m.
// If the lock is already in use, the calling goroutine
// blocks until the mutex is available.
func (m *Mutex) Lock() {// Fast path: grab unlocked mutex.if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {if race.Enabled {race.Acquire(unsafe.Pointer(m))}return}// Slow path (outlined so that the fast path can be inlined)m.lockSlow()
}// TryLock tries to lock m and reports whether it succeeded.
//
// Note that while correct uses of TryLock do exist, they are rare,
// and use of TryLock is often a sign of a deeper problem
// in a particular use of mutexes.
func (m *Mutex) TryLock() bool {old := m.stateif old&(mutexLocked|mutexStarving) != 0 {return false}// There may be a goroutine waiting for the mutex, but we are// running now and can try to grab the mutex before that// goroutine wakes up.if !atomic.CompareAndSwapInt32(&m.state, old, old|mutexLocked) {return false}if race.Enabled {race.Acquire(unsafe.Pointer(m))}return true
}
使用select模拟tryLock()
type Mutex struct {ch chan struct{}
}// init clock
func NewMutex() *Mutex {mutex := &Mutex{ch: make(chan struct{}, 1),}return mutex
}// get lock
func (m *Mutex) Lock() {m.ch <- struct{}{}
}// return lock
func (m *Mutex) Unlock() {select {case <-m.ch :default:panic("unlock the unlocked mutex")}
}// try get lock
func (m *Mutex) TryLock() bool {select {case m.ch <- struct{}{}:return truedefault:return false}
}func (m *Mutex) LockTimeout(timeout time.Duration) bool {timer := time.NewTimer(timeout)select {case <-timer.C:case m.ch <- struct{}{}:timer.Stop()return true}return false
}func (m Mutex) IsLocked() bool {return len(m.ch) == 1
}