【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
}
相关推荐
野生技术架构师3 分钟前
Java 23 种设计模式:从踩坑到精通 —— 开篇及系列介绍
java·开发语言·设计模式
Wang ruoxi4 分钟前
Pygame 小游戏——数独
开发语言·python·pygame
人道领域10 分钟前
【LeetCode刷题日记】90.子集Ⅱ--- 归纳题解
java·开发语言·leetcode
sandnes14 分钟前
把ToolUse循环做到生产级-错误处理与可靠性五件套
后端
ch.ju16 分钟前
Java Programming Chapter 4——Characteristics of inheritance
java·开发语言
复园电子17 分钟前
企业PDF批量盖章开发集成指南:API对接OA/LIMS系统,高并发落地实战
开发语言·python·pdf
SunnyDays101122 分钟前
如何使用 C# 自动调整 Excel 行高和列宽
开发语言·c#·excel
掘金者阿豪24 分钟前
全维度拆解具身智能:底层技术 + 实战落地 + 全球产业竞争
后端
秋天的一阵风28 分钟前
✨ 代码秒跳转、自动补全?全靠 LSP 和 AST!
前端·后端·ai编程
a诠释淡然34 分钟前
C++模板元编程—现代C++的黑魔法
开发语言·c++