threadsafe

threadsafe defines lock interfaces for building reusable, goroutine-safe data structures and helpers without hard-coding a concrete lock type.

Part of nurago, a collection of independent Go packages for backend services.

import "github.com/tecnickcom/nurago/pkg/threadsafe"

Package threadsafe defines lock interfaces for building reusable, goroutine-safe data structures and helpers without hard-coding a concrete lock type.

It defines two lock interfaces:

  • [Locker]: the write-lock contract (Lock and Unlock), a defined type sharing the method set of sync.Locker.
  • [RLocker]: the read-lock contract (RLock and RUnlock) used by read/write synchronization patterns.

These interfaces are embedded or referenced by concurrent containers and utility types used across multiple goroutines.

Usage

See the examples in:

  • github.com/tecnickcom/nurago/pkg/threadsafe/tsmap
  • github.com/tecnickcom/nurago/pkg/threadsafe/tsslice

Read helpers in dependent packages accept RLocker, which a plain sync.Mutex does not satisfy (it has no RLock/RUnlock). This forces callers that need shared read access to supply an sync.RWMutex-like type at compile time, rather than serializing every read behind an exclusive lock. A sync.RWMutex satisfies both Locker and RLocker, so the same lock instance can drive read and write helpers.

These interfaces only describe the locking contract; they do not enforce it. All access to the protected data must funnel through the helper functions using the same lock instance, otherwise concurrent reads and writes are not safe.

When To Use

  • You are writing a goroutine-safe type and want the caller to choose sync.Mutex or sync.RWMutex.
  • Read-heavy code should be able to declare that it only needs a shared lock.

Example

c := &counter{
	mux:    &sync.Mutex{},
	values: make(map[string]int),
}

var wg sync.WaitGroup

for range 100 {
	wg.Go(func() {
		c.inc("hits")
	})
}

wg.Wait()

fmt.Println(c.values["hits"])

// Output:
// 100

Full source is in example_threadsafe_test.go. More runnable examples are on pkg.go.dev.

Dependencies

This package reaches no external module: it uses only the Go standard library.