gate

package module
v0.0.0-...-0c466b8 Latest Latest
Warning

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

Go to latest
Published: Nov 17, 2024 License: BSD-3-Clause Imports: 1 Imported by: 0

README

Go Reference

Documentation

Overview

Package gate contains an alternative condition variable.

Example (Queue)
package main

import (
	"context"
	"fmt"
	"io"
	"slices"
	"time"

	"github.com/neild/gate"
)

// A Queue is an unbounded queue of some item.
type Queue[T any] struct {
	gate gate.Gate // set if queue is non-empty or closed
	err  error
	q    []T
}

// NewQueue returns a new queue.
func NewQueue[T any]() *Queue[T] {
	return &Queue[T]{
		gate: gate.New(false),
	}
}

// Close closes the queue, causing pending and future pop operations
// to return immediately with err.
func (q *Queue[T]) Close(err error) {
	q.gate.Lock()
	defer q.unlock()
	if q.err == nil {
		q.err = err
	}
}

// Put appends an item to the queue.
// It returns true if the item was added, false if the queue is closed.
func (q *Queue[T]) Put(v T) bool {
	q.gate.Lock()
	defer q.unlock()
	if q.err != nil {
		return false
	}
	q.q = append(q.q, v)
	return true
}

// Get removes the first item from the queue, blocking until ctx is done, an item is available,
// or the queue is closed.
func (q *Queue[T]) Get(ctx context.Context) (T, error) {
	var zero T
	if err := q.gate.WaitAndLock(ctx); err != nil {
		return zero, err
	}
	defer q.unlock()

	// WaitAndLock blocks until the gate condition is set,
	// so either the queue is closed (q.err != nil) or
	// there is at least one item in the queue.
	if q.err != nil {
		return zero, q.err
	}
	v := q.q[0]
	q.q = slices.Delete(q.q, 0, 1)
	return v, nil
}

// unlock unlocks the queue's gate,
// setting the condition to true if the queue is non-empty or closed.
func (q *Queue[T]) unlock() {
	q.gate.Unlock(q.err != nil || len(q.q) > 0)
}

func main() {
	q := NewQueue[int]()

	go func() {
		time.Sleep(1 * time.Millisecond)
		q.Put(1)
		time.Sleep(1 * time.Millisecond)
		q.Put(2)
		q.Close(io.EOF)
	}()

	fmt.Println(q.Get(context.Background()))
	fmt.Println(q.Get(context.Background()))
	fmt.Println(q.Get(context.Background()))
}
Output:

1 <nil>
2 <nil>
0 EOF

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Gate

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

A gate is a monitor (mutex + condition variable) with one bit of state.

A gate exists in one of three states:

  • locked
  • unlocked and set
  • unlocked and unset

Lock operations may be unconditional, or wait for the condition to be set. Unlock operations record the new state of the condition.

func New

func New(set bool) Gate

New returns a new, unlocked gate with the given condition state.

func (*Gate) Lock

func (g *Gate) Lock() (set bool)

Lock acquires the gate unconditionally. It reports whether the condition was set.

func (*Gate) LockIfSet

func (g *Gate) LockIfSet() (acquired bool)

LockIfSet acquires the gate if and only if the condition is set.

func (*Gate) Unlock

func (g *Gate) Unlock(set bool)

Unlock sets the condition and releases the gate.

func (*Gate) WaitAndLock

func (g *Gate) WaitAndLock(ctx context.Context) error

WaitAndLock waits until the condition is set before acquiring the gate. If the context expires, WaitAndLock returns an error and does not acquire the gate.

Jump to

Keyboard shortcuts

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