Skip to content

Instantly share code, notes, and snippets.

@liluo
Forked from chriseidhof/goroutines.swift
Created July 5, 2019 08:54
Show Gist options
  • Save liluo/e2437255cf20c5c0e1b058ff37ef57ce to your computer and use it in GitHub Desktop.
Save liluo/e2437255cf20c5c0e1b058ff37ef57ce to your computer and use it in GitHub Desktop.
goroutines.swift
import Foundation
protocol Channel: IteratorProtocol {
func send(_ value: Element?)
}
/// A blocking channel for sending values.
///
/// `send` and `receive` must run in separate separate execution contexts, otherwise you get a deadlock.
final class BlockingChannel<A>: Channel {
let producer = DispatchSemaphore(value: 0)
let consumer = DispatchSemaphore(value: 0)
private var value: A?
var done: Bool = false
func send(_ value: A?) {
producer.wait()
self.value = value
if value == nil { done = true }
consumer.signal()
}
func next() -> A? {
guard !done else { return nil }
producer.signal()
consumer.wait()
return value
}
}
final class BufferedChannel<A>: Channel {
let valueQueue = DispatchQueue(label: "sync value")
let consumer = DispatchSemaphore(value: 0)
private var values: [A] = []
var done: Bool = false
func send(_ value: A?) {
if let v = value {
self.valueQueue.sync {
self.values.append(v)
}
} else {
done = true
}
consumer.signal()
}
func next() -> A? {
guard !done else {
return values.isEmpty ? nil : values.removeFirst()
}
consumer.wait()
var result: A? = nil
valueQueue.sync {
result = values.removeFirst()
}
return result
}
}
func go(_ f: @escaping () -> ()) -> () {
DispatchQueue.global().async {
f()
}
}
infix operator <-
func <-<C, A>(lhs: C, rhs: A?) where C: Channel, C.Element == A {
lhs.send(rhs)
}
func test() {
let channel = BufferedChannel<Int>()
go {
channel <- 1
channel <- 2
channel <- nil // done
}
sleep(1)
while let value = channel.next() {
print(value)
}
}
test()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment