sync.WaitGroup and sync.Mutex patterns
Scanned 2/12/2026
Install to Claude Code
npx -y skills add JamesPrial/claudefiles --skill sync --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Sync?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/jamesprial-sync)More formats (shields.io, HTML) on the badges page.
---
name: go-sync-primitives
description: sync.WaitGroup and sync.Mutex patterns
---
# Sync Primitives
## sync.WaitGroup - Wait for Goroutines
### CORRECT
```go
func processBatch(items []string) {
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1) // BEFORE launching goroutine
go func(item string) {
defer wg.Done()
process(item)
}(item)
}
wg.Wait() // Block until all done
}
```
### WRONG - Add inside goroutine
```go
func processBatch(items []string) {
var wg sync.WaitGroup
for _, item := range items {
go func(item string) {
wg.Add(1) // WRONG: race condition
defer wg.Done()
process(item)
}(item)
}
wg.Wait() // May return early
}
```
### WRONG - Missing variable capture
```go
func processBatch(items []string) {
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go func() {
defer wg.Done()
process(item) // WRONG: captures loop variable
}()
}
wg.Wait()
}
```
## sync.Mutex - Protect Shared State
### CORRECT
```go
type Counter struct {
mu sync.Mutex
value int
}
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *Counter) Value() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
```
### WRONG - Unlocked access
```go
type Counter struct {
mu sync.Mutex
value int
}
func (c *Counter) Increment() {
c.mu.Lock()
c.value++ // What if panic happens?
c.mu.Unlock()
}
func (c *Counter) Value() int {
return c.value // WRONG: race condition
}
```
## sync.RWMutex - Multiple Readers
```go
type Cache struct {
mu sync.RWMutex
data map[string]string
}
func (c *Cache) Get(key string) (string, bool) {
c.mu.RLock() // Multiple readers OK
defer c.mu.RUnlock()
val, ok := c.data[key]
return val, ok
}
func (c *Cache) Set(key, value string) {
c.mu.Lock() // Exclusive writer
defer c.mu.Unlock()
c.data[key] = value
}
```
## Rules
### WaitGroup
1. Call `Add()` before `go` statement
2. Always use `defer wg.Done()`
3. Pass loop variables as function parameters
4. One `Add(n)` can count multiple goroutines
### Mutex
1. Always use `defer mu.Unlock()`
2. Keep critical sections small
3. Don't hold locks during I/O or slow operations
4. Use RWMutex for read-heavy workloads
5. Never copy a mutex (pass by pointer)
## sync.Once - Run Exactly Once
```go
var (
instance *Singleton
once sync.Once
)
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{}
})
return instance
}
```
## Race Detection
```bash
go test -race ./...
go run -race main.go
```

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!