12

まず、このようなシリアル キューを作成します

static dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);

次に、未知の時点で、このようにタスクがキューに追加されます

dispatch_async(queue, ^{
    // do something, which takes some time
});

最初のタスクがまだ完了していない場合、新しいタスクは最初のタスクが完了するまで待機します (もちろん、これがシリアル キューの目的です)。

しかし、キューに 5 つの新しいタスクを追加すると、元の最初のタスクがまだ実行されている間に、新しいタスク 1 番、2 番、3 番などを実行したくありませんが、取得したいタスク 1 から 4 を削除し、元の最初のタスクが終了した後、タスク 5 の実行を直接開始します。

つまり、新しいタスクを追加する場合は、待機中のタスク (現在実行中のタスクではない) をキューからポップしたいと考えています。

これには組み込みのメカニズムがありますか、それとも自分で実装する必要がありますか? 後者の場合、キュー内の単一のタスクを特定して削除するにはどうすればよいでしょうか?

4

3 に答える 3

19

ブロックが GCD ディスパッチ キューに送信されると、実行されます。キャンセルする方法はありません。ご存知のように、ブロックの実行を早期に「中止」する独自のメカニズムを実装できます。

これを行う簡単な方法は、 を使用することNSOperationQueueです。保留中の操作 (つまり、まだ実行されていない操作) をキャンセルするための実装が既に提供されており、new-ishaddOperationWithBlockメソッドを使用してブロックを簡単にキューに入れることができます。

GCDNSOperationQueueを使用して実装されていますが、ほとんどの場合、GCD の方がはるかに使いやすいと思います。NSOperationQueueただし、この場合、保留中の操作のキャンセルを既に処理しているため、使用を真剣に検討します。

于 2012-09-07T14:39:44.967 に答える
5

デビッドの答えが私を軌道に乗せることで、私はこのようにすることに成功しました

taskCounter++;
dispatch_async(queue, ^{
    if (taskCounter > 1) {
        taskCounter--;
        NSLog(@"%@", @"skip");
        return;
    }
    NSLog(@"%@", @"start");
    // do stuff
    sleep(3);
    taskCounter--;
    NSLog(@"%@", @"done");
});

taskCounterivarまたはプロパティのいずれかである必要があります(で初期化します0)。__blockその場合、属性も必要ありません。

于 2012-09-07T12:26:53.487 に答える
4

これを処理する方法は、キューに入れられたブロックに単に返す必要があることを示す ivar を使用することです。

^{
  if(!canceled) {
    ... do work
  }
}

単純なブール値も使用する必要はありません。これをより複雑にすることもできますが、一般的な考え方は、ブロックが何かを実行する前に照会する 1 つ以上の ivar を使用することです。

私はこの手法を使用して (ただし、発明したわけではありません)、大きな成功を収めています。

于 2012-09-07T11:28:15.327 に答える