Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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()
@moreindirection

This comment has been minimized.

Copy link

moreindirection commented Feb 16, 2018

Nice implementation!

Should the code inside BufferedChannel#send be inside a "valuesQueue.sync"? What if one thread sends a new value after another thread sends a nil to finish the channel? Or what if two threads simultaneously invoke next() after the channel is done?

@13hoop

This comment has been minimized.

Copy link

13hoop commented Feb 18, 2018

nice
thanks for sharing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.