import Foundation
class FIFO {
typealias DataCallback = (String) -> ()
private var data = [String]()
private var waitingDataList = [DataCallback]()
private var syncQueue = DispatchQueue(label: "FIFO.sync")
private var callBackQueue = DispatchQueue(label: "FIFO.callback", qos: .background, attributes: .concurrent)
func isFreeable() -> Bool {
return syncQueue.sync {
waitingDataList.count == 0 && data.count == 0
}
}
func isDataAvailable() -> Bool {
return syncQueue.sync {
return data.count > 0
}
}
func enqueue(value: String) {
syncQueue.sync {
data.append(value)
syncQueue.async {
while self.waitingDataList.count > 0 {
if self.data.count > 0 {
let callback = self.waitingDataList.remove(at: 0)
let val = self.data.remove(at: 0)
self.callBackQueue.async {
callback(val)
}
}
else {
return
}
}
}
}
}
func dequeue(onDataAvailable: @escaping DataCallback) {
syncQueue.sync {
if data.count > 0 {
let val = data.remove(at: 0)
callBackQueue.async {
onDataAvailable(val)
}
}
else {
waitingDataList.append(onDataAvailable)
}
}
}
}
let f = FIFO()
var producerFinished = false
print(" ******** START ******** ")
DispatchQueue.global(qos: .background).async {
for i in 1...100 {
let ti = Double(arc4random_uniform(1000)) / Double(1000)
Thread.sleep(forTimeInterval: ti)
print("Producing: \(i)")
f.enqueue(value: "product \(i)")
}
producerFinished = true
}
DispatchQueue.global(qos: .background).async {
while !producerFinished || f.isDataAvailable() {
let ti = Double(arc4random_uniform(1000)) / Double(1000)
Thread.sleep(forTimeInterval: ti)
f.dequeue {
print("Consuming \($0)")
}
}
}
repeat {
Thread.sleep(forTimeInterval: 3.0)
} while !(f.isFreeable() && producerFinished)
print(" ******** END ******** ")