Skip to content

Commit

Permalink
Rename Semaphore to AsyncSemaphore
Browse files Browse the repository at this point in the history
This avoids a conflict with Darwin.Semaphore, as well as a conflict with the module name.
  • Loading branch information
groue committed Oct 7, 2022
1 parent 78aa633 commit e16343b
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 23 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Semaphore

`Semaphore` is an object that controls access to a resource across multiple execution contexts through use of a traditional counting semaphore.
`AsyncSemaphore` is an object that controls access to a resource across multiple execution contexts through use of a traditional counting semaphore.

Unlike [`DispatchSemaphore`], `Semaphore` does not block any thread. Instead, it suspends Swift concurrency tasks.
Unlike [`DispatchSemaphore`], `AsyncSemaphore` does not block any thread. Instead, it suspends Swift concurrency tasks.

### Usage

You can use a semaphore to suspend a task and resume it later:

```swift
let semaphore = Semaphore(value: 0)
let semaphore = AsyncSemaphore(value: 0)

Task {
// Suspends the task until a signal occurs.
Expand All @@ -25,7 +25,7 @@ You can use a semaphore in order to make sure an actor's methods can't run concu

```swift
actor MyActor {
private let semaphore = Semaphore(value: 1)
private let semaphore = AsyncSemaphore(value: 1)

func serializedMethod() async {
// Makes sure no two tasks can execute self.serializedMethod() concurrently.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import Foundation
/// An object that controls access to a resource across multiple execution
/// contexts through use of a traditional counting semaphore.
///
/// Unlike `DispatchSemaphore`, ``Semaphore`` does not block any thread.
/// Unlike `DispatchSemaphore`, ``AsyncSemaphore`` does not block any thread.
/// Instead, it suspends Swift concurrency tasks.
///
/// ## Topics
Expand All @@ -41,7 +41,7 @@ import Foundation
///
/// - ``wait()``
/// - ``waitUnlessCancelled()``
public final class Semaphore {
public final class AsyncSemaphore {
/// "Waiting for a signal" is easily said, but several possible states exist.
private class Suspension {
enum State {
Expand Down Expand Up @@ -93,12 +93,12 @@ public final class Semaphore {
/// - parameter value: The starting value for the semaphore. Do not pass a
/// value less than zero.
public init(value: Int) {
precondition(value >= 0, "Semaphore requires a value equal or greater than zero")
precondition(value >= 0, "AsyncSemaphore requires a value equal or greater than zero")
self.value = value
}

deinit {
precondition(suspensions.isEmpty, "Semaphore is deallocated while some task(s) are suspended waiting for a signal.")
precondition(suspensions.isEmpty, "AsyncSemaphore is deallocated while some task(s) are suspended waiting for a signal.")
}

// MARK: - Locking
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Dispatch
import XCTest
@testable import Semaphore

final class SemaphoreTests: XCTestCase {
final class AsyncSemaphoreTests: XCTestCase {

func testSignalWithoutSuspendedTasks() async {
// Check DispatchSemaphore behavior
Expand All @@ -21,20 +21,20 @@ final class SemaphoreTests: XCTestCase {
}
}

// Test that Semaphore behaves identically
// Test that AsyncSemaphore behaves identically
do {
do {
let sem = Semaphore(value: 0)
let sem = AsyncSemaphore(value: 0)
let woken = sem.signal()
XCTAssertFalse(woken)
}
do {
let sem = Semaphore(value: 1)
let sem = AsyncSemaphore(value: 1)
let woken = sem.signal()
XCTAssertFalse(woken)
}
do {
let sem = Semaphore(value: 2)
let sem = AsyncSemaphore(value: 2)
let woken = sem.signal()
XCTAssertFalse(woken)
}
Expand All @@ -57,10 +57,10 @@ final class SemaphoreTests: XCTestCase {
XCTAssertFalse(sem.signal() != 0)
}

// Test that Semaphore behaves identically
// Test that AsyncSemaphore behaves identically
do {
// Given a task suspended on the semaphore
let sem = Semaphore(value: 0)
let sem = AsyncSemaphore(value: 0)
Task { await sem.wait() }
try await Task.sleep(nanoseconds: delay)

Expand Down Expand Up @@ -95,10 +95,10 @@ final class SemaphoreTests: XCTestCase {
wait(for: [ex2], timeout: 1)
}

// Test that Semaphore behaves identically
// Test that AsyncSemaphore behaves identically
do {
// Given a zero semaphore
let sem = Semaphore(value: 0)
let sem = AsyncSemaphore(value: 0)

// When a task waits for this semaphore,
let ex1 = expectation(description: "wait")
Expand All @@ -120,7 +120,7 @@ final class SemaphoreTests: XCTestCase {
}

func test_cancellation_while_suspended_throws_CancellationError() async throws {
let sem = Semaphore(value: 0)
let sem = AsyncSemaphore(value: 0)
let ex = expectation(description: "cancellation")
let task = Task {
do {
Expand All @@ -138,7 +138,7 @@ final class SemaphoreTests: XCTestCase {
}

func test_cancellation_before_suspension_throws_CancellationError() async throws {
let sem = Semaphore(value: 0)
let sem = AsyncSemaphore(value: 0)
let ex = expectation(description: "cancellation")
let task = Task {
// Uncancellable delay
Expand All @@ -162,7 +162,7 @@ final class SemaphoreTests: XCTestCase {

func test_that_cancellation_while_suspended_increments_the_semaphore() async throws {
// Given a task cancelled while suspended on a semaphore,
let sem = Semaphore(value: 0)
let sem = AsyncSemaphore(value: 0)
let task = Task {
try await sem.waitUnlessCancelled()
}
Expand All @@ -189,7 +189,7 @@ final class SemaphoreTests: XCTestCase {

func test_that_cancellation_before_suspension_increments_the_semaphore() async throws {
// Given a task cancelled before it waits on a semaphore,
let sem = Semaphore(value: 0)
let sem = AsyncSemaphore(value: 0)
let task = Task {
// Uncancellable delay
await withUnsafeContinuation { continuation in
Expand Down Expand Up @@ -236,7 +236,7 @@ final class SemaphoreTests: XCTestCase {
let maxCount = 10
for count in 1...maxCount {
let runner = Runner()
let sem = Semaphore(value: count)
let sem = AsyncSemaphore(value: count)

// Spawn many concurrent tasks
await withThrowingTaskGroup(of: Void.self) { group in
Expand Down Expand Up @@ -273,7 +273,7 @@ final class SemaphoreTests: XCTestCase {
let maxCount = 10
for count in 1...maxCount {
let runner = Runner()
let sem = Semaphore(value: count)
let sem = AsyncSemaphore(value: count)

// Spawn many concurrent tasks
await withThrowingTaskGroup(of: Void.self) { group in
Expand Down

0 comments on commit e16343b

Please sign in to comment.