40

最近、特定のシリアルディスパッチキューで特定のブロックの同期実行を保証するために使用できる関数が必要になりました。この共有関数は、そのキューですでに実行されているものから呼び出される可能性があるため、同じキューへの同期ディスパッチによるデッドロックを防ぐために、このケースを確認する必要がありました。

私はこれを行うために次のようなコードを使用しました:

void runSynchronouslyOnVideoProcessingQueue(void (^block)(void))
{
    dispatch_queue_t videoProcessingQueue = [GPUImageOpenGLESContext sharedOpenGLESQueue];

    if (dispatch_get_current_queue() == videoProcessingQueue)
    {
        block();
    }
    else
    {
        dispatch_sync(videoProcessingQueue, block);
    }
}

この関数は、を使用して、dispatch_get_current_queue()この関数が実行されているキューのIDを判別し、それをターゲットキューと比較します。一致するものがある場合は、関数がすでに実行されているため、そのキューにディスパッチせずにブロックをインラインで実行することを認識しています。

このような比較を行うために使用することが適切であるかどうかについて矛盾することを聞いたことがdispatch_get_current_queue()あり、ヘッダーに次の表現があります。

デバッグとロギングの目的でのみ推奨:

それがグローバルキューの1つであるか、コード自体が作成したキューでない限り、コードは返されたキューについていかなる仮定もしてはなりません。そのキューがdispatch_get_current_queue()によって返されるキューでない場合、コードはキューへの同期実行がデッドロックから安全であると想定してはなりません。

さらに、iOS 6.0(ただし、Mountain Lionではまだ)では、GCDヘッダーがこの関数を非推奨としてマークするようになりました。

この機能をこのように使うべきではないように思えますが、代わりに何を使うべきかわかりません。メインキューを対象とした上記のような関数の場合、を使用できます[NSThread isMainThread]が、デッドロックを防ぐために、カスタムシリアルキューの1つで実行されているかどうかを確認するにはどうすればよいですか?

4

2 に答える 2

36

を使用して任意の識別子を割り当てますdispatch_queue_set_specific()。その後、 を使用して識別子を確認できますdispatch_get_specific()

dispatch_get_specific()現在のキューから開始し、キーが現在のキューに設定されていない場合はターゲット キューを上に移動するため、これは便利です。これは通常は問題になりませんが、場合によっては便利です。

于 2012-10-09T19:09:07.893 に答える
1

これは非常に簡単な解決策です。手動で使用するほどパフォーマンスは高くありません-それに関するメトリックはありませdispatch_queue_set_specificん。dispatch_get_specific

#import <libkern/OSAtomic.h>

BOOL dispatch_is_on_queue(dispatch_queue_t queue)
{
    int key;
    static int32_t incrementer;
    CFNumberRef value = CFBridgingRetain(@(OSAtomicIncrement32(&incrementer)));
    dispatch_queue_set_specific(queue, &key, value, nil);
    BOOL result = dispatch_get_specific(&key) == value;
    dispatch_queue_set_specific(queue, &key, nil, nil);
    CFRelease(value);
    return result;
}
于 2016-06-21T11:40:57.157 に答える