9

次のコマンドでシリアル ディスパッチ キューを作成しました。

dispatch_queue_t serialQueue = dispatch_queue_create("com.unique.name.queue", DISPATCH_QUEUE_SERIAL);

このシリアル キューを使用して、呼び出し元のスレッドに戻る必要のない作業を非同期で自動的に実行しながら、クラス アクセスのスレッド セーフを確保したいと考えています。

- (void)addObjectToQueue:(id)object
{
    dispatch_async(serialQueue, ^{
        // process object and add to queue
    }); 
}

- (BOOL)isObjectInQueue:(id)object
{
    __block BOOL returnValue = NO;
    dispatch_sync(serialQueue, ^{
        // work out return value
    });
    return returnValue;
} 

addObjectToQueue: メソッドを呼び出した場合、すぐに isObjectInQueue: メソッドを呼び出します。それらは同じ順序で実行されることが保証されていますか、それとも isObjectInQueue が最初に実行されますか?

つまり、dispatch_async は、呼び出し元のスレッドをブロックしないことを除いて、dispatch_sync (ブロックをすぐにスケジュールする) とまったく同じように動作しますか?

同様の質問で回答が双方向になるのを見たので、できればAppleのドキュメントに裏付けられた決定的な回答を探しています。

4

2 に答える 2

13

それらは同じ順序で実行されることが保証されていますか?

はい。

isObjectInQueue最初に実行しますか?

はい。

両方の答えに「はい」の理由は、スレッド化を検討する必要があるためです。そもそもシリアルキューを使用しているのはおそらくこれが理由です。そのキューへのアクセスをスレッドセーフにしています。

基本的に、ブロックはシリアル キューに置かれた順序で実行されます。それは100%保証されています。ただし、複数のスレッドがこれに取り組んでいる場合、1 つのスレッドが最初にキューから何かを読み取るために、別のスレッドが追加する機会を得る前に、キューから何かを読み取る可能性があります。

dispatch_syncつまり、dispatch_asyncは、呼び出し元のスレッドをブロックしないことを除いて、(ブロックをすぐにスケジュールする)とまったく同じように動作しますか?

それは正しい。どちらの場合も、ブロックはキューに追加されます。すぐに追加されます。dispatch_syncブロックが終了するのを待ってから戻りますが、dispatch_asyncすぐに戻ります。

于 2013-01-12T12:49:26.983 に答える
2

dispatch_asyncあなたの質問は、キュー操作をまだ実行している間、メインスレッドが実行され続けるかということだと思いますか? それは明示的な言及に値するので、そうはならないと思います。どちらかといえば、 dispatch_async.3でこれを見つけました。これは、これが事実であることを示唆しています:

概念的には、dispatch_sync() は、dispatch_async() の便利なラッパーであり、ブロックの完了を待機するセマフォと、ブロックの完了を通知するブロックのラッパーが追加されています。

実際、queue.c の dispatch_asyncのソース コードをたどると、ブロックがフォアグラウンドでキューに入れられ、その後でのみ、実行が を呼び出したコードに戻ることがわかりますdispatch_async。したがって、キューがシリアルの場合、同じスレッドからのdispatch_asynca が後に続くと、ブロックが順番にキューに入れられます。dispatch_sync

ブロック(およびシリアルキュー内の前のすべてのブロック)の実行が完了するまでブロックされるためdispatch_sync、コードは正しいでしょう。isObjectInQueue:以前に追加されたオブジェクトがキューにあるかどうかを正しく報告します。

edit : マルチスレッド環境では、上記のコードを次のように記述します。

- (void)addObjectToQueue:(id)object
{
    dispatch_barrier_async(_queue, ^{
        // process object and add to queue
    });
}

- (BOOL)isObjectInQueue:(id)object
{
    __block BOOL returnValue = NO;
    dispatch_sync(_queue, ^{
        // work out return value
    });
    return returnValue;
} 

各メソッドの実行は、別のスレッドを優先して任意の時点で延期できるためです。

于 2013-01-12T12:47:14.817 に答える