sync.Mutex là một struct chứa trạng thái khóa (state, sema). Copy nó là copy trạng thái đó ra một bản riêng, và từ đó hai bản khóa độc lập với nhau — vùng loại trừ tương hỗ biến mất, hai goroutine vào critical section cùng lúc.
Tệ hơn: copy đúng lúc mutex đang bị giữ thì bản sao ra đời với trạng thái "đã khóa" mà không có ai sở hữu. Ai Lock bản sao đó sẽ chặn vĩnh viễn.
Việc copy hay xảy ra ngầm, không cần dấu = tường minh:
type Counter struct {
mu sync.Mutex
n int
}
func (c Counter) Inc() { // value receiver: c is a fresh copy on every call
c.mu.Lock()
defer c.mu.Unlock()
c.n++ // mutates the copy, locks a private mutex
}Các đường copy ngầm khác: truyền struct vào hàm theo giá trị, gán struct này cho struct kia, for _, v := range items (biến v là bản sao), trả về struct thay vì con trỏ từ hàm khởi tạo, và append một slice struct.
Cách phòng: dùng pointer receiver cho mọi method của struct có chứa mutex, và luôn truyền *T. go vet có analyzer copylock báo passes lock by value: Counter contains sync.Mutex. Nó áp dụng cho mọi kiểu implement sync.Locker cũng như WaitGroup, Once, RWMutex, atomic.Int64 — nên bật go vet ./... trong CI thay vì trông vào review thủ công.