Skip to content

Commit

Permalink
docs: clarify examples
Browse files Browse the repository at this point in the history
  • Loading branch information
neilotoole committed Jan 19, 2024
1 parent 78c90b3 commit c347a56
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 17 deletions.
20 changes: 12 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@
[`fifomu`](https://pkg.go.dev/github.com/neilotoole/fifomu) is a Go
package that provides a [`Mutex`](https://pkg.go.dev/github.com/neilotoole/fifomu#Mutex)
whose [`Lock`](https://pkg.go.dev/github.com/neilotoole/fifomu#Mutex.Lock) method returns
the lock to callers in FIFO call order. This is unlike [`sync.Mutex`](https://pkg.go.dev/sync#Mutex),
the lock to callers in FIFO call order. This is in contrast to [`sync.Mutex`](https://pkg.go.dev/sync#Mutex),
where a single goroutine can repeatedly lock and unlock and relock the mutex
without handing off to other lock waiter goroutines (until after a 1ms
starvation threshold, at which point `sync.Mutex` enters "starvation mode"
for those starved waiters, but that's too late for our use case).
without handing off to other lock waiter goroutines (that is, until after a 1ms
starvation threshold, at which point `sync.Mutex` enters a FIFO "starvation mode"
for those starved waiters, but that's too late for some use cases).

`fifomu.Mutex` implements the exported methods of `sync.Mutex` and thus is
a drop-in replacement (and by extension, also implements [`sync.Locker`](https://pkg.go.dev/sync#Locker)).
It also provides a bonus context-aware [`LockContext`](https://pkg.go.dev/github.com/neilotoole/fifomu#Mutex.LockContext)
method.

Note: unless you need the FIFO behavior, you should prefer `sync.Mutex`
because, for typical workloads, its "greedy-relock" behavior requires
less goroutine switching and yields better performance. See the [benchmarks](#benchmarks)
Note: unless you need the FIFO behavior, you should prefer `sync.Mutex`.
For typical workloads, its "greedy-relock" behavior requires less goroutine
switching and yields better performance. See the [benchmarks](#benchmarks)
section below.


Expand All @@ -44,23 +44,27 @@ func main() {
mu := &fifomu.Mutex{}
mu.Lock()
defer mu.Unlock()

// ... Do something critical
}
```

Additionally, `fifomu` provides a context-aware
[`Mutex.LockContext`](https://pkg.go.dev/github.com/neilotoole/fifomu#Mutex.LockContext)
method that blocks until the mutex is available or ctx is done, returning the
value of `context.Cause(ctx.Err())`.
value of [`context.Cause(ctx)`](https://pkg.go.dev/context#Cause).

```go
func foo(ctx context.Context) error {
mu := &fifomu.Mutex{}
if err := mu.LockContext(ctx); err != nil {
// Oh dear, ctx was cancelled
return err
}
defer mu.Unlock()

// ... Do something critical

return nil
}
```
Expand Down
19 changes: 10 additions & 9 deletions fifomu.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package fifomu provides a Mutex whose Lock method returns
// the lock to callers in FIFO call order. This is unlike sync.Mutex, where
// Package fifomu provides a Mutex whose Lock method returns the lock to
// callers in FIFO call order. This is in contrast to sync.Mutex, where
// a single goroutine can repeatedly lock and unlock and relock the mutex
// without handing off to other lock waiter goroutines (until after a 1ms
// starvation threshold, at which point sync.Mutex enters "starvation mode"
// for those starved waiters, but that's too late for our use case).
// without handing off to other lock waiter goroutines (that is, until after
// a 1ms starvation threshold, at which point sync.Mutex enters a FIFO
// "starvation mode" for those starved waiters, but that's too late for some
// use cases).
//
// fifomu.Mutex implements the exported methods of sync.Mutex and thus is
// a drop-in replacement (and by extension also implements sync.Locker).
// It also provides a bonus context-aware Mutex.LockContext method.
//
// Note: unless you need the FIFO behavior, you should prefer sync.Mutex,
// because, for typical workloads, its "greedy-relock" behavior requires
// less goroutine switching and yields better performance.
// Note: unless you need the FIFO behavior, you should prefer sync.Mutex.
// For typical workloads, its "greedy-relock" behavior requires less goroutine
// switching and yields better performance.
package fifomu

import (
Expand Down Expand Up @@ -66,7 +67,7 @@ func (m *Mutex) Lock() {
// If the lock is already in use, the calling goroutine
// blocks until the mutex is available or ctx is done.
//
// On failure, LockContext returns context.Cause(ctx.Err()) and
// On failure, LockContext returns context.Cause(ctx) and
// leaves the mutex unchanged.
//
// If ctx is already done, LockContext may still succeed without blocking.
Expand Down

0 comments on commit c347a56

Please sign in to comment.