Semaphore

Inherits from: Object

A counting semaphore for limiting concurrent access to a resource pool.

A semaphore manages a fixed number of permits. acquire blocks until a permit is available; release returns one. Use critical: to automatically acquire before and release after evaluating a block.

Semaphore new creates a binary semaphore (1 permit). Semaphore new: n creates a semaphore with n permits.

Example
Semaphore new capacity           "=> 1"
(Semaphore new: 3) capacity     "=> 3"
(Semaphore new: 3) available    "=> 3"
Semaphore new hasAvailablePermits  "=> true"
(Semaphore new: 2) isFull       "=> false"

| s <Semaphore> |
s := Semaphore new: 3.
s tryAcquire.
s available                      "=> 2"

s := Semaphore new.
s tryAcquire                     "=> true"

s := Semaphore new.
s tryAcquire.
s tryAcquire                     "=> false"

s := Semaphore new.
s tryAcquire.
s isFull                         "=> true"

s := Semaphore new: 2.
s critical: [42]                 "=> 42"
Example
"Rate-limiting concurrent work to 3 at a time"
| sem <Semaphore> wg <WaitGroup> |
sem := Semaphore new: 3.
wg := WaitGroup new.
1 to: 10 do: [:i |
    wg wrap: [sem critical: [Process sleep: 100]]
].
wg wait

Class Methods

primitives

class primNew:

uncategorized

class new

Create a binary semaphore with a single permit.

Example
Semaphore new capacity   "=> 1"
Semaphore new available  "=> 1"
class new:

Create a semaphore with the given number of permits.

Example
(Semaphore new: 5) capacity   "=> 5"
(Semaphore new: 5) available  "=> 5"

Instance Methods

primitives

primAcquire
primAvailable
primCapacity
primCritical:
primRelease
primTryAcquire

uncategorized

acquire

Acquire a permit, blocking if none are available. Use tryAcquire for a non-blocking alternative.

Example
| sem <Semaphore> |
sem := Semaphore new: 2.
sem acquire.
sem release
available

Return the number of currently available permits.

Example
(Semaphore new: 3) available  "=> 3"

| s <Semaphore> |
s := Semaphore new: 3.
s tryAcquire.
s tryAcquire.
s available                    "=> 1"
capacity

Return the total permit capacity of the semaphore.

Example
Semaphore new capacity         "=> 1"
(Semaphore new: 10) capacity  "=> 10"
critical:

Evaluate aBlock while holding a permit. The permit is automatically released when the block finishes, even if an error occurs.

Example
(Semaphore new: 2) critical: [42]  "=> 42"

| s <Semaphore> |
s := Semaphore new: 1.
s critical: ['done'].
s available                         "=> 1"
hasAvailablePermits

Return true if the semaphore has at least one available permit.

Example
Semaphore new hasAvailablePermits   "=> true"

| s <Semaphore> |
s := Semaphore new.
s tryAcquire.
s hasAvailablePermits               "=> false"
ifAvailable:

Execute aBlock only if a permit is immediately available. Returns the block's result if executed, or nil if no permit was available.

Example
Semaphore new ifAvailable: [42]     "=> 42"

| s <Semaphore> |
s := Semaphore new.
s tryAcquire.
s ifAvailable: [42]                 "=> nil"
isFull

Return true if all permits are currently in use.

Example
(Semaphore new: 2) isFull          "=> false"

| s <Semaphore> |
s := Semaphore new.
s tryAcquire.
s isFull                            "=> true"
printString

Return a string describing the semaphore and its permit state.

Example
Semaphore new printString
"=> 'a Semaphore (1/1 available)'"

(Semaphore new: 3) printString
"=> 'a Semaphore (3/3 available)'"
release

Release a permit back to the semaphore, potentially unblocking a waiting process.

Example
| s <Semaphore> |
s := Semaphore new: 1.
s tryAcquire.
s available     "=> 0"
s release.
s available     "=> 1"
tryAcquire

Try to acquire a permit without blocking. Returns true if a permit was acquired, false if none were available.

Example
Semaphore new tryAcquire       "=> true"

| s <Semaphore> |
s := Semaphore new.
s tryAcquire.
s tryAcquire                   "=> false"
withPermit:

Alias for critical:. Evaluate aBlock while holding a permit.

Example
Semaphore new withPermit: [42]  "=> 42"