giovedì 26 ottobre 2017

FIFO queue in Swift 4 with GCD

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 ******** ")

Nessun commento: