面试题-用 Go 实现非阻塞互斥锁

刷牛客看到的问题,尝试解决下并记录下来。

利用 chan + select 实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
type Mutex struct {
	c chan struct{} 
}

func NewMutex() *Mutex {
	m := &Mutex{
		c: make(chan struct{}, 1),
	}

	m.c <- struct{}{}
	return m
}

func (m *Mutex) Lock() bool {
	select {
	case <- m.c:
		return true
	default:
		return false
	}
}

func (m *Mutex) UnLock() {
	select {
	case <- m.c:
		panic("没有上锁,却调用解锁")
	default:
	}
	m.c <- struct{}{}
}


var count = 0

// Test
func main() {
	mutex := NewMutex()
	m := make(map[int]int)
	
	for i := 0; i < 100; i++ {
		go func(i int) {
			for {
				if mutex.Lock() {
					m[count] = count
					fmt.Printf("goroutinue %d : %d\n", i, count)
					count++
					mutex.UnLock()
				}
				// 防止解锁后立刻抢锁,大概率还是被这个 G 抢占
				time.Sleep(time.Second) 
			}
		}(i)
	}

	var c  chan struct{}
	<- c
}

这里有两种校验锁是否满足并发安全的方法:

  1. 使用 map 作为校验并发安全性,因为 map 内部有并发安全的校验机制,如果发生并发读写,会 panic
  2. 为了观看方便,print 打印出来

End

0%