Example of what a running Go program looks like from https://go.dev/tour/concurrency/9.
Using the delve
debugger: https://github.com/go-delve/delve
Use delve
to compile and debug:
$ dlv debug mutex-counter.go
(dlv) l main.main:3
Showing /home/rmanes/Downloads/mutex-counter.go:34 (PC: 0x49b82f)
29: }
30:
31: func main() {
32: c := SafeCounter{v: make(map[string]int)}
33: for i := 0; i < 1000; i++ {
34: go c.Inc("somekey")
35: }
36:
37: time.Sleep(time.Second)
38: fmt.Println(c.Value("somekey"))
39: }
Set a breakpoint and continue to stop our process:
(dlv) b /home/rmanes/Downloads/mutex-counter.go:37
Breakpoint 1 set at 0x49b899 for main.main() ./mutex-counter.go:37
(dlv) c
> [Breakpoint 1] main.main() ./mutex-counter.go:37 (hits goroutine(1):1 total:1) (PC: 0x49b899)
32: c := SafeCounter{v: make(map[string]int)}
33: for i := 0; i < 1000; i++ {
34: go c.Inc("somekey")
35: }
36:
=> 37: time.Sleep(time.Second)
38: fmt.Println(c.Value("somekey"))
39: }
40:
Check all goroutines:
(dlv) goroutines
* Goroutine 1 - User: ./mutex-counter.go:37 main.main (0x49b899) (thread 3871629)
Goroutine 17 - User: /usr/lib/golang/src/runtime/proc.go:403 runtime.gopark (0x43ce1c) [force gc (idle)]
Goroutine 18 - User: /usr/lib/golang/src/runtime/proc.go:403 runtime.gopark (0x43ce1c) [GC sweep wait]
Goroutine 19 - User: /usr/lib/golang/src/runtime/proc.go:403 runtime.gopark (0x43ce1c) [GC scavenge wait]
Goroutine 20 - User: /usr/lib/golang/src/runtime/proc.go:403 runtime.gopark (0x43ce1c) [finalizer wait]
Goroutine 924 - User: /usr/lib/golang/src/runtime/sema.go:77 sync.runtime_SemacquireMutex (0x468005) (thread 3871649)
Goroutine 1020 - User: ./mutex-counter.go:34 main.main.gowrap1 (0x49b960)
[7 goroutines]
Switch to a goroutine running in the for loop:
(dlv) goroutine 924
Switched from 1020 to 924 (thread 3871649)
(dlv) goroutine
Thread 3871649 at /usr/lib/golang/src/runtime/proc.go:1122
Goroutine 924:
Runtime: /usr/lib/golang/src/runtime/proc.go:1122 runtime.casgstatus (0x43ea31)
User: /usr/lib/golang/src/runtime/sema.go:77 sync.runtime_SemacquireMutex (0x468005)
Go: ./mutex-counter.go:34 main.main (0x49b890)
Start: ./mutex-counter.go:16 main.(*SafeCounter).Inc (0x49b520)
Stack for that goroutine:
(dlv) bt
0 0x000000000043ea31 in runtime.casgstatus
at /usr/lib/golang/src/runtime/proc.go:1122
1 0x0000000000441bfb in runtime.execute
at /usr/lib/golang/src/runtime/proc.go:3107
2 0x000000000044385e in runtime.schedule
at /usr/lib/golang/src/runtime/proc.go:3918
3 0x00000000004442b8 in runtime.goexit0
at /usr/lib/golang/src/runtime/proc.go:4181
4 0x000000000046930e in runtime.mcall
at /usr/lib/golang/src/runtime/asm_amd64.s:458
5 0x000000000043ce1c in runtime.gopark
at /usr/lib/golang/src/runtime/proc.go:402
6 0x000000000043cea5 in runtime.goparkunlock
at /usr/lib/golang/src/runtime/proc.go:408
7 0x000000000044d92d in runtime.semacquire1
at /usr/lib/golang/src/runtime/sema.go:160
8 0x0000000000468005 in sync.runtime_SemacquireMutex
at /usr/lib/golang/src/runtime/sema.go:77
9 0x000000000047d2cd in sync.(*Mutex).lockSlow
at /usr/lib/golang/src/sync/mutex.go:171
10 0x000000000047d065 in sync.(*Mutex).Lock
at /usr/lib/golang/src/sync/mutex.go:90
11 0x000000000049b549 in main.(*SafeCounter).Inc
at ./mutex-counter.go:17
12 0x000000000049b991 in main.main.gowrap1
at ./mutex-counter.go:34
13 0x000000000046b1c1 in runtime.goexit
at /usr/lib/golang/src/runtime/asm_amd64.s:1695
Check the frame which is trying to claim a mutex (some other goroutine currently has it):
(dlv) frame 11
> [Breakpoint 1] main.main() ./mutex-counter.go:37 (hits goroutine(1):1 total:1) (PC: 0x49b899)
> runtime.casgstatus() /usr/lib/golang/src/runtime/proc.go:1122 (PC: 0x43ea31)
Warning: debugging optimized function
Frame 11: ./mutex-counter.go:17 (PC: 49b549)
12: v map[string]int
13: }
14:
15: // Inc increments the counter for the given key.
16: func (c *SafeCounter) Inc(key string) {
=> 17: c.mu.Lock()
18: // Lock so only one goroutine at a time can access the map c.v.
19: c.v[key]++
20: c.mu.Unlock()
21: }
22:
Check the struct and the mutex in it:
(dlv) p c
(*main.SafeCounter)(0xc00008c270)
*main.SafeCounter {
mu: sync.Mutex {state: 2, sema: 1},
v: map[string]int [
"somekey": 998,
],}