Created
May 15, 2019 21:10
-
-
Save monadplus/11ddd0142d2e644d8636291e9f844980 to your computer and use it in GitHub Desktop.
Exercise: implement a concurrent semaphore
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
abstract class Semaphore[F[_]] { | |
/** | |
* Returns the number of permits currently available. Always non-negative. | |
* | |
* May be out of date the instant after it is retrieved. | |
* Use `[[tryAcquire]]` or `[[tryAcquireN]]` if you wish to attempt an | |
* acquire, returning immediately if the current count is not high enough | |
* to satisfy the request. | |
*/ | |
def available: F[Long] | |
/** | |
* Obtains a snapshot of the current count. May be negative. | |
* | |
* Like [[available]] when permits are available but returns the number of permits | |
* callers are waiting for when there are no permits available. | |
*/ | |
def count: F[Long] | |
/** | |
* Acquires `n` permits. | |
* | |
* The returned effect semantically blocks until all requested permits are | |
* available. Note that acquires are statisfied in strict FIFO order, so given | |
* `s: Semaphore[F]` with 2 permits available, an `acquireN(3)` will | |
* always be satisfied before a later call to `acquireN(1)`. | |
* | |
* @param n number of permits to acquire - must be >= 0 | |
*/ | |
def acquireN(n: Long): F[Unit] | |
/** Acquires a single permit. Alias for `[[acquireN]](1)`. */ | |
def acquire: F[Unit] = acquireN(1) | |
/** | |
* Acquires `n` permits now and returns `true`, or returns `false` immediately. Error if `n < 0`. | |
* | |
* @param n number of permits to acquire - must be >= 0 | |
*/ | |
def tryAcquireN(n: Long): F[Boolean] | |
/** Alias for `[[tryAcquireN]](1)`. */ | |
def tryAcquire: F[Boolean] = tryAcquireN(1) | |
/** | |
* Releases `n` permits, potentially unblocking up to `n` outstanding acquires. | |
* | |
* @param n number of permits to release - must be >= 0 | |
*/ | |
def releaseN(n: Long): F[Unit] | |
/** Releases a single permit. Alias for `[[releaseN]](1)`. */ | |
def release: F[Unit] = releaseN(1) | |
/** | |
* Returns an effect that acquires a permit, runs the supplied effect, and then releases the permit. | |
*/ | |
def withPermit[A](t: F[A]): F[A] | |
/** | |
* Modify the context `F` using natural isomorphism `f` with `g`. | |
*/ | |
def imapK[G[_]](f: F ~> G, g: G ~> F): Semaphore[G] = | |
new TransformedSemaphore(this, f, g) | |
} | |
private type State[F[_]] = Either[Queue[(Long, Deferred[F, Unit])], Long] | |
private abstract class AbstractSemaphore[F[_]](state: Ref[F, State[F]])(implicit F: Async[F]) extends Semaphore[F] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment