golang--通过chan实现互斥锁

通过chan实现互斥锁

利用 select+chan 的方式,很容易实现 TryLock、Timeout 的功能

原理

chan中有一把锁lock 可以保护chan中的字段,同时chan的send和recev 两种角色存在一种hapends-befores的关系。

type hchan struct {
	qcount   uint           // total data in the queue
	dataqsiz uint           // size of the circular queue
	buf      unsafe.Pointer // points to an array of dataqsiz elements
	elemsize uint16
	closed   uint32
	elemtype *_type // element type
	sendx    uint   // send index
	recvx    uint   // receive index
	recvq    waitq  // list of recv waiters
	sendq    waitq  // list of send waiters

	// lock protects all fields in hchan, as well as several
	// fields in sudogs blocked on this channel.
	//
	// Do not change another G's status while holding this lock
	// (in particular, do not ready a G), as this can deadlock
	// with stack shrinking.
	lock mutex
}

第一种方法

第一种方法指的是chan的cap为1,放入一个元素代表获得锁,谁获得了这个元素则获取到锁。

type Mutex struct {
	ch chan struct{}
}

// init clock
func NewMutex() *Mutex {
	mutex := &Mutex{
		ch: make(chan struct{}, 1),
	}
	mutex.ch <- struct{}{}
	return mutex
}

// get lock
func (m *Mutex) Lock() {
	<-m.ch
}

// return lock
func (m *Mutex) Unlock() {
	select {
	case m.ch <- struct{}{}:
	default:
		panic("unlock the unlocked mutex")
	}
}

// try get lock
func (m *Mutex) TryLock() bool {
	select {
	case <-m.ch:
		return true
	default:
		return false
	}
}

func (m *Mutex) LockTimeout(timeout time.Duration) bool {
	timer := time.NewTimer(timeout)
	select {
	case <-timer.C:
	case <-m.ch:
		timer.Stop()
		return true
	}
	return false
}

func (m Mutex) IsLocked() bool {
	return len(m.ch) == 0
}

第二种方法

第二种法法指的是chan的cap为1,空槽为锁,能成功发送到chan的则获取到了锁。

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 true
	default:
		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
}

引用:go 并发编程实战课 — 鸟窝

你可能感兴趣的:(golang,golang,并发)