All skills
cxuu avatar

/go-concurrency

@91f0c2e
by Charles Xucxuu/golang-skills165 stars
19

Use when writing concurrent Go code — goroutines, channels, mutexes, or thread-safety guarantees. Also use when parallelizing work, fixing data races, or protecting shared state, even if the user doesn't explicitly mention concurrency primitives. Does not cover context.Context patterns (see go-context).

Use this Skill: https://skilld.dev/gh/cxuu/golang-skills/go-concurrency

This session only. Nothing lands on disk.

referencesSYNC-PRIMITIVES.md

≈635 tokens on demand. Your agent reads this file only when SKILL.md points to it.

Sync Primitives Patterns

Detailed patterns for mutexes and atomic operations — covering mutex embedding pitfalls and type-safe atomic access.


Don't Embed Mutexes

If you use a struct by pointer, the mutex should be a non-pointer field. Do not embed the mutex on the struct, even if the struct is not exported.

// Bad: Embedded mutex exposes Lock/Unlock as part of API
type SMap struct {
    sync.Mutex // Lock() and Unlock() become methods of SMap
    data map[string]string
}

func (m *SMap) Get(k string) string {
    m.Lock()
    defer m.Unlock()
    return m.data[k]
}
// Good: Named field keeps mutex as implementation detail
type SMap struct {
    mu   sync.Mutex
    data map[string]string
}

func (m *SMap) Get(k string) string {
    m.mu.Lock()
    defer m.mu.Unlock()
    return m.data[k]
}

With the bad example, Lock and Unlock methods are unintentionally part of the exported API. With the good example, the mutex is an implementation detail hidden from callers.


Atomic Operations: Full Example

The standard sync/atomic package operates on raw types (int32, int64, etc.), making it easy to forget to use atomic operations consistently.

// Bad: Easy to forget atomic operation
type foo struct {
    running int32 // atomic
}

func (f *foo) start() {
    if atomic.SwapInt32(&f.running, 1) == 1 {
        return // already running
    }
    // start the Foo
}

func (f *foo) isRunning() bool {
    return f.running == 1 // race! forgot atomic.LoadInt32
}
// Good: Type-safe atomic operations
type foo struct {
    running atomic.Bool
}

func (f *foo) start() {
    if f.running.Swap(true) {
        return // already running
    }
    // start the Foo
}

func (f *foo) isRunning() bool {
    return f.running.Load() // can't accidentally read non-atomically
}

The atomic.Bool, atomic.Int64, etc. types (available in stdlib sync/atomic since Go 1.19, or via go.uber.org/atomic) add type safety by hiding the underlying type.


Channel Direction Examples

Specifying direction prevents accidental misuse:

// Good: Direction specified - clear ownership
func sum(values <-chan int) int {
    total := 0
    for v := range values {
        total += v
    }
    return total
}
// Bad: No direction - allows accidental misuse
func sum(values chan int) (out int) {
    for v := range values {
        out += v
    }
    close(values) // Bug! This compiles but shouldn't happen.
}

Source: SKILL.md on GitHub

No alerts17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill provides comprehensive guidelines and best practices for writing concurrent Go code, focusing on goroutine lifetimes, channel patterns, and synchronization primitives. It includes references to trusted community resources and tools. No security issues were detected.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer6mo

    2 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 91f0c2e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 3 months ago

README badge

README badge for cxuu/golang-skills/go-concurrency