2017-08-11 20 views
1

iOS開発者の役割に関するインタビューでこの質問をしました。プロトコルを使用して同時実行スレッドを実装するにはどうすればよいですか?

// Please design a read-write task queue where you can tag the reader task with label, 
// where the the task with the same label should be executed sequentially, and the 
// tasks with different labels could be executed concurrently. However, the writer 
// would get the exclusive access where no concurrent task would happen at the 
// same time with the writer task 

// For example: 
protocol ConcurrentQueueWithSerialization { 
    // Submits a labeled task. 
    // All tasks with the same label will be serialized. 
    // Tasks with different labels will run concurrently. 
    // Use this method to submit a "read" operation from a particular reader. 
    func async(with label: String, task: @escaping() -> Void) 

    // Submits a task that will run concurrently with all other tasks regardless of their labels. 
    func async(task: @escaping() -> Void) 

    // Submits a labeled and delayed task. 
    func asyncAfter(deadline: DispatchTime, with label: String, task: @escaping() -> Void) 

    // Submits an unlabeled and delayed task. 
    func asyncAfter(deadline: DispatchTime, task: @escaping() -> Void) 

    // Submits a barrier task. Only one barrier task is allowed to run at a time. 
    // Works as a critical section for the queue. 
    // Use this method to submit a writer task. 
    func asyncBarrier(task: @escaping() -> Void) 
} 

class MyDispatchQueue: ConcurrentQueueWithSerialization { 
    //TODO: write your implementation 

} 

Interviewerは、上記のプロトコルをMyDispatchQueueクラスに実装するように求めました。私は試しましたが、解決策が見つかりませんでした。私を助けてください。前もって感謝します。

+0

SOはコード作成サービスではありません。何を試しましたか?あなたはどんな問題にぶつかったのですか? – Alexander

+0

あなたの質問には要件だけが含まれています。あなた自身がこの問題を解決するための努力を示しているわけではありません。このサイトは無料の「私たちはあなたの(自宅)仕事をしている」サービスではないので、この質問にあなたの試みを加えてください。それを超えて:[ヘルプ]を見て、ここでどのように/何を尋ねるかを学んでください。ありがとう! – GhostCat

答えて

6

以前は、ターゲットキューを使用することを推奨しましたが、プライマリコンカレントキューを作成し、その名前付きキューのシリアルキューを作成してから、そのプライマリコンカレントキューにすべてをディスパッチしました。ターゲット・キュー・アプローチとは異なり、これは名前の付いたキューにディスパッチされたタスクの名前付きのキューにディスパッチされたタスクのスケジューリングを尊重します。

この実装では、「fred」と「ginger」という名前のキューのタスクを追加した例(Instrumentの「Points of Interest」プロファイル)と、名前のないキューに追加されたもの障壁タスクを追加し、前述の各キューにさらに2つのタスクを追加しました。

enter image description here

あなたが見ることができるように、それは無名のキューが同時であり、すべてのこれらのキューは、互いに並行している、という名前のキューの連続性を尊重しますが、障壁は、すべての間で障壁となっています待ち行列

class MyDispatchQueue: ConcurrentQueueWithSerialization { 
    private var namedQueues = [String: DispatchQueue]() 
    private var queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".target", attributes: .concurrent) 
    private let lock = NSLock() 

    private func queue(with label: String) -> DispatchQueue { 
     lock.lock() 
     defer { lock.unlock() } 

     if let queue = namedQueues[label] { return queue } 

     let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + "." + label) 
     namedQueues[label] = queue 
     return queue 
    } 

    func async(with label: String, task: @escaping() -> Void) { 
     queue.async { 
      self.queue(with: label).sync(execute: task) 
     } 
    } 

    func async(task: @escaping() -> Void) { 
     queue.async(execute: task) 
    } 

    func asyncAfter(deadline: DispatchTime, with label: String, task: @escaping() -> Void) { 
     queue.asyncAfter(deadline: deadline) { 
      self.queue(with: label).sync(execute: task) 
     } 
    } 

    func asyncAfter(deadline: DispatchTime, task: @escaping() -> Void) { 
     queue.asyncAfter(deadline: deadline, execute: task) 
    } 

    func asyncBarrier(task: @escaping() -> Void) { 
     queue.async(flags: .barrier, execute: task) 
    } 
} 

注、私はまた、このクラスのスレッド安全性を確保するために、namedQueues配列へのアクセスを同期します。

関連する問題