【go每日一题】 channel实现mutex锁

代码实现

go 复制代码
package test

import (
	"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的源码(内部实际上通过信号量实现)

go 复制代码
// 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.state
	if 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()

go 复制代码
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
}
相关推荐
摇滚侠20 小时前
Spring Boot 3零基础教程,IOC容器中组件的注册,笔记08
spring boot·笔记·后端
rit84324991 天前
基于MATLAB的模糊图像复原
开发语言·matlab
fie88891 天前
基于MATLAB的声呐图像特征提取与显示
开发语言·人工智能
程序员小凯1 天前
Spring Boot测试框架详解
java·spring boot·后端
_extraordinary_1 天前
Java SpringMVC(二) --- 响应,综合性练习
java·开发语言
你的人类朋友1 天前
什么是断言?
前端·后端·安全
@。1241 天前
对于灰度发布(金丝雀发布)的了解
开发语言·前端
程序员小凯1 天前
Spring Boot缓存机制详解
spring boot·后端·缓存
i学长的猫1 天前
Ruby on Rails 从0 开始入门到进阶到高级 - 10分钟速通版
后端·ruby on rails·ruby
用户21411832636021 天前
别再为 Claude 付费!Codex + 免费模型 + cc-switch,多场景 AI 编程全搞定
后端