concurrency

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 5, 2025 License: MIT Imports: 2 Imported by: 0

README

concurrency

Concurrency utilities for Go

📦 go get github.com/lif0/pkg/concurrency@latest
🧪 Requires Go 1.19+

build go reference concurrency coverage concurrency report card


Contents


Overview

The concurrency package provides lightweight, efficient concurrency primitives for Go, designed for correctness and performance with minimal memory allocations. It simplifies concurrent programming tasks in Go applications.


Requirements

  • Go 1.19 or higher

Installation

To install the package, run:

go get github.com/lif0/pkg/concurrency@latest

Features

Semaphore

The Semaphore type provides a counting semaphore to limit the number of concurrent holders of a shared resource. It supports both limited and unlimited capacity, with methods like Acquire, AcquireContext, TryAcquire, Release, InUse, and Cap.

Example: Limited Semaphore
package main

import (
    "fmt"
    "github.com/lif0/pkg/concurrency"
)

func main() {
    // Create a semaphore with a capacity of 3
    sem := concurrency.NewSemaphore(3)

    // Acquire a slot
    sem.Acquire()
    fmt.Printf("Acquired a slot, in use: %d/%d\n", sem.InUse(), sem.Cap())
    
    // Perform critical section work
    // ...

    // Release the slot
    sem.Release()
    fmt.Println("Released a slot")
}
Example: Unlimited Semaphore
package main

import (
    "fmt"
    "github.com/lif0/pkg/concurrency"
)

func main() {
    // Create an unlimited semaphore
    sem := concurrency.NewSemaphore(0)

    // Acquire is a no-op for unlimited semaphores
    sem.Acquire()
    fmt.Printf("Acquired (no-op), in use: %d, cap: %d\n", sem.InUse(), sem.Cap())

    // Perform work
    // ...

    // Release is a no-op for unlimited semaphores
    sem.Release()
    fmt.Println("Released (no-op)")
}
Example: Context-Aware Acquisition
package main

import (
    "context"
    "fmt"
    "time"
    "github.com/lif0/pkg/concurrency"
)

func main() {
    // Create a semaphore with a capacity of 2
    sem := concurrency.NewSemaphore(2)
    
    // Create a context with a timeout
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
    defer cancel()

    // Attempt to acquire a slot with context
    if err := sem.AcquireContext(ctx); err != nil {
        fmt.Printf("Failed to acquire: %v\n", err)
        return
    }
    fmt.Printf("Acquired a slot with context, in use: %d/%d\n", sem.InUse(), sem.Cap())

    // Perform work
    // ...

    // Release the slot
    sem.Release()
    fmt.Println("Released a slot")
}
Example: Non-Blocking Acquisition
package main

import (
    "fmt"
    "github.com/lif0/pkg/concurrency"
)

func main() {
    // Create a semaphore with a capacity of 1
    sem := concurrency.NewSemaphore(1)

    // Acquire the only slot
    sem.Acquire()
    fmt.Printf("Acquired a slot, in use: %d/%d\n", sem.InUse(), sem.Cap())

    // Try to acquire another slot without blocking
    if sem.TryAcquire() {
        fmt.Println("Acquired another slot")
    } else {
        fmt.Println("Failed to acquire: no slots available")
    }

    // Release the slot
    sem.Release()
    fmt.Println("Released a slot")
}
WithLock

WithLock is a helper function that executes an action while holding a lock.
It guarantees that the lock will always be released, even if the action panics.

import (
	"github.com/lif0/pkg/concurrency"
)

func main() {
	var mu sync.Mutex
	counter := 0
	var wg sync.WaitGroup

	for i := 0; i < 5; i++ {
		wg.Add(1)
        wg.Go(func() {
            for j := 0; j < 100; j++ {
				concurrency.WithLock(&mu, func() {
					counter++
				})
			}
        })
	}

	wg.Wait()
	fmt.Println("Final counter:", counter) // Always 500
}

Roadmap

  • FanIn/FanOut patterns for channel-based concurrency.
  • Future/Promise constructs for asynchronous programming.
  • Michael-Scott Queue (MS Queue) for lock-free concurrent queues.

Contributions and feature suggestions are welcome 🤗.


License

MIT

Documentation

Overview

Package concurrency provides concurrency utilities.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func WithLock

func WithLock(mutex sync.Locker, action func())

WithLock executes the given action while holding the provided lock.

It accepts any sync.Locker (e.g., *sync.Mutex, *sync.RWMutex) and a function with no parameters or return values. If the action is nil, nothing is executed.

The lock is guaranteed to be released after the action completes, even if the action panics or returns early.

Types

type Semaphore

type Semaphore struct {
	// contains filtered or unexported fields
}

Semaphore is a counting semaphore that bounds the number of concurrent holders.

The zero value (and a nil *Semaphore) is an unlimited semaphore: all acquire operations succeed immediately and Release is a no-op.

All methods are safe for concurrent use by multiple goroutines.

func NewSemaphore

func NewSemaphore(capacity uint) *Semaphore

NewSemaphore returns a semaphore with the provided capacity.

If capacity <= 0, it returns an unlimited semaphore, for which all acquire operations succeed immediately and Release does nothing.

func (*Semaphore) Acquire

func (s *Semaphore) Acquire()

Acquire obtains one slot from s, blocking until a slot is available. For an unlimited semaphore, Acquire is a no-op.

func (*Semaphore) AcquireContext

func (s *Semaphore) AcquireContext(ctx context.Context) error

AcquireContext attempts to obtain one slot, blocking until a slot is available or the context is canceled or its deadline is exceeded. It returns ctx.Err() if the context is done first. For an unlimited semaphore, AcquireContext returns nil immediately.

func (*Semaphore) Cap

func (s *Semaphore) Cap() int

Cap returns the maximum number of concurrent holders (the capacity). For an unlimited semaphore, Cap returns 0.

func (*Semaphore) InUse

func (s *Semaphore) InUse() int

InUse reports the current number of acquired slots. For an unlimited semaphore, InUse returns 0.

func (*Semaphore) Release

func (s *Semaphore) Release()

Release releases one previously acquired slot. On a limited semaphore, calling Release without a matching acquire panics. On an unlimited semaphore, Release is a no-op.

func (*Semaphore) TryAcquire

func (s *Semaphore) TryAcquire() bool

TryAcquire attempts to obtain one slot without blocking. It returns true if a slot was acquired and false otherwise. For an unlimited semaphore, TryAcquire always returns true.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL