【iPhoneアプリ】他にもまだまだあった「マルチスレッド」について dispatch_xxxxx編続き
今回もまた、「マルチスレッド」についてです。
前回の「dispatch_xxxxx」について
ですが、記載しきれなかった為、今回は続きを記載します。
続きで記載出来なかったdispatch_xxxxについて
■dispatch_barrier_async
・非同期処理の完了を待つ、もしくは非同期処理の間にblock構文の内容を
処理したい場合
※処理は非同期で行いますが、前後の処理の整合性を取るため見た目は同期です。
引数 | 説明 |
---|---|
dispatch_queue_t | ディスパチキューオブジェクト |
dispatch_block_t | タスク処理が書かれたblock構文 |
<注意>
グローバルキュー、プライベートのシリアルキューでは機能しません。
プライベートのコンカレントキューのみ機能します。
こんな感じのプログラムを書きます。
- (IBAction)thread_Button:(UIButton*)sender { dispatch_queue_t queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT); //非同期処理1 dispatch_apply(5,queue,^(size_t i){ NSLog(@"非同期1_処理回数:%d",(int)i); }); //非同期処理2 dispatch_async(queue,^{ for(int i=0;i<5;i++){ NSLog(@"非同期2_処理回数:%d",(int)i); } }); //バリアされた非同期処理 dispatch_barrier_async(queue,^{ NSLog(@"dispatch_barrier_async"); }); //非同期処理3 dispatch_apply(5,queue,^(size_t i){ NSLog(@"非同期3_処理回数:%d",(int)i); }); }
結果はこんな感じです。
labo[21289:60b] 非同期1_処理回数:0 labo[21289:60b] 非同期1_処理回数:2 labo[21289:60b] 非同期1_処理回数:3 labo[21289:60b] 非同期1_処理回数:4 labo[21289:1803] 非同期1_処理回数:1 labo[21289:3707] 非同期2_処理回数:0 labo[21289:3707] 非同期2_処理回数:1 labo[21289:3707] 非同期2_処理回数:2 labo[21289:3707] 非同期2_処理回数:3 labo[21289:3707] 非同期2_処理回数:4 labo[21289:3707] dispatch_barrier_async labo[21289:60b] 非同期3_処理回数:0 labo[21289:60b] 非同期3_処理回数:1 labo[21289:60b] 非同期3_処理回数:2 labo[21289:60b] 非同期3_処理回数:4 labo[21289:1803] 非同期3_処理回数:3
dispatch_barrier_asyncを使うと、先行処理「非同期処理1」「非同期処理2」が
終わるまで処理実行を待つ、そして、dispatch_barrier_async内の処理が完了するまで
後続の「非同期処理3」の処理は実行されない。
■dispatch_barrier_async_f
・非同期処理の完了を待つ、もしくは非同期処理の間にblock構文ではなく、関数を
利用したい場合。
※処理は非同期で行いますが、前後の処理の整合性を取るため見た目は同期です。
引数 | 説明 |
---|---|
dispatch_queue_t | ディスパチキューオブジェクト |
void * | 関数の引数:汎用ポインタ |
dispactch_function | 関数名 |
<注意>
グローバルキュー、プライベートのシリアルキューでは機能しません。
プライベートのコンカレントキューのみ機能します。
こんな感じのプログラムを書きます。
- (IBAction)thread_Button:(UIButton*)sender { dispatch_queue_t queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT); //非同期処理1 dispatch_apply(5,queue,^(size_t i){ NSLog(@"非同期1_処理回数:%d",(int)i); }); //非同期処理2 dispatch_async(queue,^{ for(int i=0;i<5;i++){ NSLog(@"非同期2_処理回数:%d",(int)i); } }); //バリアされた非同期処理 dispatch_barrier_async_f(queue,(void *)int_obj,barrier_method); //非同期処理3 dispatch_apply(5,queue,^(size_t i){ NSLog(@"非同期3_処理回数:%d",(int)i); }); } //呼び出すメソッド void barrier_method(void *context) { NSLog(@"引数のvoid_ポインタ値:%d",(int)context); }
結果はこんな感じです。
labo[21326:60b] 非同期1_処理回数:0 labo[21326:1803] 非同期1_処理回数:1 labo[21326:60b] 非同期1_処理回数:2 labo[21326:1803] 非同期1_処理回数:3 labo[21326:60b] 非同期1_処理回数:4 labo[21326:1803] 非同期2_処理回数:0 labo[21326:1803] 非同期2_処理回数:1 labo[21326:1803] 非同期2_処理回数:2 labo[21326:1803] 非同期2_処理回数:3 labo[21326:1803] 非同期2_処理回数:4 labo[21326:1803] 引数のvoid_ポインタ値:20 labo[21326:60b] 非同期3_処理回数:0 labo[21326:1803] 非同期3_処理回数:1 labo[21326:1803] 非同期3_処理回数:3 labo[21326:1803] 非同期3_処理回数:4 labo[21326:60b] 非同期3_処理回数:2
dispatch_barrier_async_fを使うと、先行処理「非同期処理1」「非同期処理2」が
終わるまで処理実行を待つ、そして、dispatch_barrier_async内の処理が完了するまで
後続の「非同期処理3」の処理は実行されない。
■dispatch_barrier_sync
・非同期処理の完了を待つ、もしくは非同期処理の間にblock構文の処理をする場合。
※処理は同期で行います。
引数 | 説明 |
---|---|
dispatch_queue_t | ディスパチキューオブジェクト |
dispatch_block_t | タスク処理が書かれたblock構文 |
<注意>
グローバルキュー、プライベートのシリアルキューでは機能しません。
プライベートのコンカレントキューのみ機能します。
こんな感じのプログラムを書きます。
- (IBAction)thread_Button:(UIButton*)sender { dispatch_queue_t queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT); //非同期処理1 dispatch_apply(5,queue,^(size_t i){ NSLog(@"非同期1_処理回数:%d",(int)i); }); //非同期処理2 dispatch_async(queue,^{ for(int i=0;i<5;i++){ NSLog(@"非同期2_処理回数:%d",(int)i); } }); //バリアされた非同期処理 dispatch_barrier_sync(queue,^{ NSLog(@"dispatch_barrier_async"); }); //非同期処理3 dispatch_apply(5,queue,^(size_t i){ NSLog(@"非同期3_処理回数:%d",(int)i); }); }
結果はこんな感じです。
labo[21348:1803] 非同期1_処理回数:1 labo[21348:60b] 非同期1_処理回数:0 labo[21348:60b] 非同期1_処理回数:3 labo[21348:1803] 非同期1_処理回数:2 labo[21348:60b] 非同期1_処理回数:4 labo[21348:1803] 非同期2_処理回数:0 labo[21348:1803] 非同期2_処理回数:1 labo[21348:1803] 非同期2_処理回数:2 labo[21348:1803] 非同期2_処理回数:3 labo[21348:1803] 非同期2_処理回数:4 labo[21348:60b] dispatch_barrier_async labo[21348:60b] 非同期3_処理回数:0 labo[21348:60b] 非同期3_処理回数:2 labo[21348:60b] 非同期3_処理回数:3 labo[21348:1803] 非同期3_処理回数:1 labo[21348:60b] 非同期3_処理回数:4
dispatch_barrier_sync_fを使うと、先行処理「非同期処理1」「非同期処理2」が
終わるまで処理実行を待つ、そして、dispatch_barrier_async内の処理が完了するまで
後続の「非同期処理3」の処理は実行されない。
■dispatch_barrier_sync_f
・非同期処理の完了を待つ、もしくは非同期処理の間にblock構文ではなく、関数を
利用したい場合。
※処理は同期で行います。
引数 | 説明 |
---|---|
dispatch_queue_t | ディスパチキューオブジェクト |
void * | 関数の引数:汎用ポインタ |
dispactch_function | 関数名 |
<注意>
グローバルキュー、プライベートのシリアルキューでは機能しません。
プライベートのコンカレントキューのみ機能します。
こんな感じのプログラムを書きます。
- (IBAction)thread_Button:(UIButton*)sender { dispatch_queue_t queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT); //非同期処理1 dispatch_apply(5,queue,^(size_t i){ NSLog(@"非同期1_処理回数:%d",(int)i); }); //非同期処理2 dispatch_async(queue,^{ for(int i=0;i<5;i++){ NSLog(@"非同期2_処理回数:%d",(int)i); } }); //バリアされた非同期処理 dispatch_barrier_async_f(queue,(void *)int_obj,barrier_method); //非同期処理3 dispatch_apply(5,queue,^(size_t i){ NSLog(@"非同期3_処理回数:%d",(int)i); }); } //呼び出すメソッド void barrier_method(void *context) { NSLog(@"引数のvoid_ポインタ値:%d",(int)context); }
結果はこんな感じです。
labo[21358:60b] 非同期1_処理回数:0 labo[21358:1803] 非同期1_処理回数:1 labo[21358:1803] 非同期1_処理回数:2 labo[21358:60b] 非同期1_処理回数:4 labo[21358:1803] 非同期1_処理回数:3 labo[21358:1803] 非同期2_処理回数:0 labo[21358:1803] 非同期2_処理回数:1 labo[21358:1803] 非同期2_処理回数:2 labo[21358:1803] 非同期2_処理回数:3 labo[21358:1803] 非同期2_処理回数:4 labo[21358:60b] 引数のvoid_ポインタ値:20 labo[21358:60b] 非同期3_処理回数:0 labo[21358:1803] 非同期3_処理回数:1 labo[21358:1803] 非同期3_処理回数:3 labo[21358:60b] 非同期3_処理回数:2 labo[21358:1803] 非同期3_処理回数:4
dispatch_barrier_sync_fを使うと、先行処理「非同期処理1」「非同期処理2」が
終わるまで処理実行を待つ、そして、dispatch_barrier_async内の処理が完了するまで
後続の「非同期処理3」の処理は実行されない。
■dispatch_suspend
・キューの処理を一時的に中断させる。
<注意>
プライベートのシリアルキュー、コンカレントキューのみ機能します。
こんな感じのプログラムを書きます。
- (IBAction)thread_Button:(UIButton*)sender { dispatch_queue_t con_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT); dispatch_apply(5,con_queue,^(size_t i){ NSLog(@"非同期1_処理回数:%d",(int)i); }); //con_queueを一時的に停止 dispatch_suspend(con_queue); dispatch_apply(5,con_queue,^(size_t i){ NSLog(@"非同期2_処理回数:%d",(int)i); }); }
結果はこんな感じです。
labo[21465:60b] 非同期1_処理回数:0 labo[21465:1803] 非同期1_処理回数:1 labo[21465:1803] 非同期1_処理回数:3 labo[21465:60b] 非同期1_処理回数:2 labo[21465:1803] 非同期1_処理回数:4
dispatch_suspendがの処理以降は、「con_queue」キューが一時停止されているため
処理がされていない。
また、シリアルキューとコンカレントの2つのキューを組み合わせて
処理を行ってみる。
こんな感じのプログラムを記載します。
- (IBAction)thread_Button:(UIButton*)sender { dispatch_queue_t con_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT); dispatch_queue_t sri_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_SERIAL); dispatch_apply(5,con_queue,^(size_t i){ NSLog(@"非同期1_処理回数:%d",(int)i); }); //con_queueを一時的に停止 dispatch_suspend(con_queue); dispatch_apply(5,sri_queue,^(size_t i){ NSLog(@"非同期4_処理回数:%d",(int)i); }); //con_queueを再開 dispatch_resume(con_queue);
結果はこんな感じです。
labo[21499:60b] 非同期1_処理回数:0 labo[21499:60b] 非同期1_処理回数:2 labo[21499:60b] 非同期1_処理回数:3 labo[21499:60b] 非同期1_処理回数:4 labo[21499:1803] 非同期1_処理回数:1 labo[21499:60b] 非同期4_処理回数:0 labo[21499:60b] 非同期4_処理回数:1 labo[21499:60b] 非同期4_処理回数:2 labo[21499:60b] 非同期4_処理回数:3 labo[21499:60b] 非同期4_処理回数:4
dispatch_suspendがの処理以降は、「con_queue」キューが一時停止されているが
次の処理が「sri_queue」で別キューの為、処理が継続される。
■dispatch_suspend
・一時的に中断させていた、キューを再開させる。
<注意>
プライベートのシリアルキュー、コンカレントキューのみ機能します。
こんな感じのプログラムを書きます。
- (IBAction)thread_Button:(UIButton*)sender { dispatch_queue_t con_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT); dispatch_apply(5,con_queue,^(size_t i){ NSLog(@"非同期1_処理回数:%d",(int)i); }); //con_queueを一時的に停止 dispatch_suspend(con_queue); //mainキュー処理 for(int i=0;i<5;i++){ NSLog(@"main_処理回数:%d",(int)i); } //con_queueを再開 dispatch_resume(con_queue); dispatch_apply(5,con_queue,^(size_t i){ NSLog(@"非同期2_処理回数:%d",(int)i); });
結果はこんな感じです。
labo[21508:60b] 非同期1_処理回数:0 labo[21508:1803] 非同期1_処理回数:1 labo[21508:60b] 非同期1_処理回数:2 labo[21508:1803] 非同期1_処理回数:3 labo[21508:60b] 非同期1_処理回数:4 labo[21508:60b] main_処理回数:0 labo[21508:60b] main_処理回数:1 labo[21508:60b] main_処理回数:2 labo[21508:60b] main_処理回数:3 labo[21508:60b] main_処理回数:4 labo[21508:60b] 非同期2_処理回数:0 labo[21508:60b] 非同期2_処理回数:2 labo[21508:60b] 非同期2_処理回数:3 labo[21508:60b] 非同期2_処理回数:4 labo[21508:1803] 非同期2_処理回数:1
dispatch_suspendがの処理以降は、「con_queue」キューが停止され
「main」キューの処理後のdispatch_resumeで「con_queue」キューの処理が再開される。
■dispatch_semaphore
・非同期処理から同期処理を行いたい場合に利用する。
▼dispatch_semaphore_create()
・初期値を使用して新しい「CountingSemaphore」を作成します。
型名 | 説明 |
---|---|
long値 | カウントの数 |
▼dispatch_semaphore_signal
・「CountingSemaphore」をインクリメント(増やす)します。
型名 | 説明 |
---|---|
dispatch_semaphore_t | カウンティングセマフォ |
▼dispatch_semaphore_wait
・「CountingSemaphore」をデクリメント(減らす)します。
型名 | 説明 |
---|---|
dispatch_semaphore_t | カウンティングセマフォ |
dispatch_time_t | タイムアウト時間設定 |
<注意>
グローバルキュー、プライベートのシリアルキュー、コンカレントキューのみ
機能します。
こんな感じのプログラムを書きます。
- (IBAction)thread_Button:(UIButton*)sender { dispatch_queue_t con_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); dispatch_async(sri_queue, ^{ //async内の処理開始 for (int i = 1; i <= 5; i++) { NSLog(@"非同期_async内処理_%d:%p",i,[NSThread currentThread]); } //非同期処理完了 dispatch_semaphore_signal(semaphore); } NSLog(@"非同期_async外処理:%p",[NSThread currentThread]); //非同期処理終了待ち dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"同期_メイン処理:%p",[NSThread currentThread]); }
結果はこんな感じです。
20:54:39.125 labo[22427:60b] 非同期_async外処理:0x14556c60 20:54:39.126 labo[22427:1803] 非同期_async内処理_1:0x1465b080 20:54:39.126 labo[22427:1803] 非同期_async内処理_2:0x1465b080 20:54:39.128 labo[22427:1803] 非同期_async内処理_3:0x1465b080 20:54:39.129 labo[22427:1803] 非同期_async内処理_4:0x1465b080 20:54:39.130 labo[22427:1803] 非同期_async内処理_5:0x1465b080 20:54:39.131 labo[22427:60b] 同期_メイン処理:0x14556c60
ログを見ると「非同期_async内処理」「非同期_async外処理」両方の処理が終わるまで
「同期_メイン処理」が待っているため、非同期処理から同期処理が可能となります。
■どのように非同期から同期になっているのか
プログラム解説
動作のイメージ
dispatch_semaphoreを複数用いた場合のイメージ
ちなみに、参考に「dispatch_semaphore」を利用しない場合は、以下のような
感じになります。
プログラムはこんな感じです。
- (IBAction)thread_Button:(UIButton*)sender { dispatch_queue_t con_queue = dispatch_queue_create("jp.test.sample", DISPATCH_QUEUE_CONCURRENT); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); dispatch_async(sri_queue, ^{ for (int i = 1; i <= 5; i++) { NSLog(@"非同期_async内処理_%d:%p",i,[NSThread currentThread]); } }); NSLog(@"非同期_async外処理:%p",[NSThread currentThread]); NSLog(@"同期_メイン処理:%p",[NSThread currentThread]);
結果はこんな感じです。
labo[22733:60b] 非同期_async外処理:0x14e525b0 labo[22733:1803] 非同期_async内処理_1:0x14d7dec0 labo[22733:60b] 同期_メイン処理:0x14e525b0 labo[22733:1803] 非同期_async内処理_2:0x14d7dec0 labo[22733:1803] 非同期_async内処理_3:0x14d7dec0 labo[22733:1803] 非同期_async内処理_4:0x14d7dec0 labo[22733:1803] 非同期_async内処理_5:0x14d7dec0
上記の結果、非同期処理を待たずに同期処理がされているのが
わかると思います。
■スレッド処理作成時に使えるログ出力方法
NSObjectの「NSThread」の以下のメソッドを使います。
▼isMainThread
メインスレッドを利用しているのかを確認します。
・記載例
NSLog(@"MainThread使用中:%d", [NSThread isMainThread]);
・ログ
MainThread使用中:1 //0:未使用 //1:利用中
▼isMultiThreaded
マルチスレッドを利用しているのかを確認します。
・記載例
NSLog(@"MainThread使用中:%d", [NSThread isMainThread]);
・ログ
MultiThread使用中:1 //0:未使用 //1:利用中
▼currentThread
現在使用中のスレッドオブジェクトのアドレス値が返ってきます。
・記載例
NSLog(@"スレッドオブジェクト値:%p",[NSThread currentThread]);
・ログ
スレッドオブジェクト値:0x15574c70