0

私はいくつかのスレッドを持っていて、すべて正常に機能したら、アクションごとに1度だけmyMergeBlockメソッドを呼び出す必要があります。後でmyMergeBlockに電話できるようにしたいので、私はdispatch_onceを使用できません。iOS機能がセッションごとに1回だけ呼び出されるようにする

いくつかの擬似コードは次のようになりますが、まだスレッドセーフではありません。また、

BOOL worker1Finished, worker2Finished, worker3Finished; 

void (^mergeBlock)(void) = ^{ 
    if (worker1Finished && worker2Finished && worker3Finished) 
     dispatch_async(queue, myMergeBlock); // Must dispatch this only once 
} 

void (^worker1)(void) = ^{ 
    ... 
    worker1Finished = YES; 
    mergeBlock(); 
} 

void (^worker2)(void) = ^{ 
    ... 
    worker2Finished = YES; 
    mergeBlock(); 
} 

void (^worker3)(void) = ^{ 
    ... 
    worker3Finished = YES; 
    mergeBlock(); 
} 

、労働者が呼ばれる方法に基づいて、私はそれらを直接呼び出すことはありませんが、その代わりとして関数に渡します議論

+0

なぜ上記の作業はできませんか?私には大丈夫だと思う。 – CodaFi

答えて

3

ディスパッチグループを使用します。最初にグループを作成し、グループ内の3人のワーカーをスケジュールしてから、そのグループに通知ブロックを追加します。 それは次のようになります。

//create dispatch group 
dispatch_group_t myWorkGroup = dispatch_group_create(); 

//get one of the global concurrent queues 
dispatch_queue_t myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL); 

//submit your work blocks 
dispatch_group_async(myWorkGroup, myQueue, worker1); 
dispatch_group_async(myWorkGroup, myQueue, worker2); 
dispatch_group_async(myWorkGroup, myQueue, worker3); 

//set the mergeBlock to be submitted when all the blocks in the group are completed 
dispatch_group_notify(myWorkGroup, myQueue, mergeBlock); 

//release the group as you no longer need it 
dispatch_release(myWorkGroup); 

あなたがグループにハングアップし、ご希望の場合は、後でそれを再利用することができます。通知の前に作業をスケジュールするようにしてください。通知を最初にスケジュールしようとすると、すぐに通知されます。

私はこのコードをテストしていませんが、私のプロジェクトではdispatch_groupsを使用しています。

1

これは非常に乱雑で低レベルです。 Concurrency Programming Guideで説明したように、Operation Queuesとディスパッチグループとセマフォを見ましたか?私は彼らがあなたの問題に簡単な解決策を提供するかもしれないと思う。

+0

実際、drekkaのように、中央集中ディスパッチグループ機能を使用すると、グループ内のすべてのタスクが完了したときに何かを実行するオプションがあります。 – Pochi

+0

私はこれらのドキュメントを読んだことがあります。実際に条件付きのmutexを使うことを考えていました。私は、 '[Object doSomethingWithBlock:^ {}]'のように、非同期的に渡されたブロックを実行するような作業者を呼び出すので、操作キューが役立つかどうかはわかりません。 – Dex

0

LionまたはiOS 5以降をターゲティングする場合は、ブロックが非グローバルな並行キューにディスパッチされる限り、barrier blocksを使用できます。たとえば:

dispatch_queue_t customConcurrentQueue = dispatch_queue_create("customQueue", DISPATCH_QUEUE_CONCURRENT); 
dispatch_async(customConcurrentQueue, worker1); 
dispatch_async(customConcurrentQueue, worker2); 
dispatch_async(customConcurrentQueue, worker3); 
dispatch_barrier_async(customConcurrentQueue, mergeBlock); 

//Some time later, after you're sure all of the blocks have executed. 
dispatch_queue_release(customConcurrentQueue); 

バリアブロックは、結局、以前に提出されたブロックの実行が完了した、とバリアブロックの後に提出されたブロックは、バリアブロックが完了するまで待つことを余儀なくされる実行されます。ここでも、明らかにすべき理由から、グローバルキューでバリアブロックを使用することはできません。独自の並行キューを作成する必要があります。

関連する問題