GCDにおけるシリアル・パラレルとasync・syncの違い
3328 ワード
* author:conowen@
* E-mail:[email protected]
キューは1つ以上のタスクで構成され、これらのタスクが実行を開始すると、スレッドに割り当てられて実行されます.
シリアル・キュー、パラレル・キュー
GCDプログラミングでは、キューコードを次のように作成します.
dispatch_queue_t queue_t_concurrent = dispatch_queue_create("com.conowen.concurrent", DISPATCH_QUEUE_CONCURRENT);//concurrent
dispatch_queue_t queue_t_serial = dispatch_queue_create("com.conowen.serial", DISPATCH_QUEUE_SERIAL);//serial
DISPATCH_QUEUE_SERIALの値はNULL
[タスクA,タスクB,タスクC,タスクD]がシリアルキューに順番に置かれて実行されると,最終的に結果が得られる順番もABCDの順番であり,パラレルキューで実行されると結果の順番はランダムである.
async、sync
async
dispatch_の使用asyncはブロックを呼び出します.例えば、
dispatch_async(myQueue,myBlock);
というmyBlockはmyQueueキューのキューの最後に置かれて実行を待っています.このmyBlockタスクはシリアルとパラレルではありません.myQueueがパラレルであれば、このmyBlockタスクはパラレルで、myQueueがシリアルキューであれば、このMyBlockはシリアルで実行されますが、dispatch_asyncはすぐに終わり、戻ります.dispatch_async(myQueue, ^{
//do something
});
sync
dispatch_の使用syncは、
dispatch_sync(myQueue,myBlock);
のようにmyBlockタスクをmyQueueの上に置いて実行しますが、dispatch_syncはこのmyBlockの実行が完了するまで待機します.つまり、現在のdispatch_をブロックし続けます.syncが存在するスレッドはmyQueueキュー内のmyBlockタスクが実行されるまで戻ります.キューとスレッドの関係
iOSには、シリアル・キュー、コンカレント・キュー、グローバル・キュー(パラレル)、プライマリ・キュー(シリアル)が一般的です.
まず、プライマリ・スレッド・キュー(シリアル)について説明します.同期または非同期にかかわらず、プライマリ・スレッドでのみ実行されます.
同期(sync)の場合、プライマリ・スレッド・キュー(シリアル)が送信されますが、現在のスレッドがプライマリ・スレッドでない場合、Blockのタスクはプライマリ・スレッドのみで、現在のスレッドではありません.
GCDテクノロジーを使用してマルチスレッドを実装すると、GCDはスレッドのライフサイクル(スレッドの作成、タスクのスケジュール、スレッドの破棄)を自動的に管理します.
クラシックなデッドロック問題
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
^{NSLog(@"2");}
というBlockはdispatch_get_main_queue()
のメインシリアルキューで実行されるが、シリアルキューであるため、Blockはすぐに実行されるわけではないので、dispatch_sync
はメインスレッドをブロックし、main_queue//
のBlockの実行が完了するのを待つが、メインスレッドがブロックされているため、Blockのコードは永遠に実行されず、これによるデッドロックとなる.syncシリアルキュー
上のプライマリ・スレッドのデッドロックの問題はsyncがシリアル・キューで実行されていることです(プライマリ・スレッドはシリアル・キューです)
syncパラレルキュー
ただし、次のコードであればデッドロックは発生しません.
dispatch_queue_t queue_t_concurrent = dispatch_queue_create("com.conowen.concurrent", DISPATCH_QUEUE_CONCURRENT);//concurrent
dispatch_async(queue_t_concurrent, ^{
dispatch_sync(queue_t_concurrent, ^{
NSLog(@"2");
});
});
Blockはパラレルキュー(キューに並ばなくてもよい)ですぐに実行され、結果が返されるため、
dispatch_sync
はBlock結果をずっと待っている状態が現れるのを待つことはなく、デッドロックは発生しません.だからアップルは
dispatch_get_current_queue
の方法を廃棄しました.以下のコードがデッドロックになるのを恐れています.
dispatch_queue_t queue_t_serial = dispatch_queue_create("com.conowen.serial", DISPATCH_QUEUE_SERIAL);//serial
dispatch_async(queue_t_serial, ^{
dispatch_sync(dispatch_get_current_queue(), ^{
NSLog(@"0");
});
});