とりあえず今日はセマフォを使ってみたい
Javaでよくあるインスタンスによるロックしか実はまだよくわからない感じなので*1、とりあえず叩いてみますね。
セマフォを使わない場合
// エキスパートObjCからの引用 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); NSMutableArray *array = [[NSMutableArray alloc] init]; for (int i = 0; i < 100000; ++i) { dispatch_async(queue, ^ { [array addObject:[NSNumber numberWithInt:i]]; }); }
// 実行すると i = 961くらいでクラッシュした Sunaba(69383,0x70000e7b2000) malloc: *** error for object 0x7fb575010400: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug
セマフォを使う場合
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // Dispatch Semaphoreはカウンタ0の時は待つ、1以上の時は減算して待たずに進む // 引数の値でカウンタを初期化した dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); NSMutableArray *array = [[NSMutableArray alloc] init]; for (int i = 0; i < 100000; ++i) { dispatch_async(queue, ^ { // semaphoreのカウントが1以上になるまで dispatch_semaphore_wait の行で待つ // semaphoreのカウントが1以上の場合、1減算して先に進む。 // 二つ目の引数はsemaphoreのカウントが1以上になるまで、どの程度の時間を待つか // DISPATCH_TIME_FOREVER => 永遠になる dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); [array addObject:[NSNumber numberWithInt:i]]; // 排他制御したい場所が終わったので、セマフォのカウンタを1加算 // dispatch_semaphore_wait で待っているスレッドがあれば一番最初のスレッドから処理を再開する dispatch_semaphore_signal(semaphore); }); }
セマフォを使う場合(待ち時間が長かったら待つの中断して先に進みたい場合)
dispatch_semaphore_wait
では、セマフォのカウントが増えるまで待つ時間の上限を指定することができます。
そして、 dispatch_semaphore_wait
の戻り値からスマフォのカウンタが0であるものの時間の上限に達したために処理を進めたのか、スマフォのカウンタが1以上になったため処理を進めたのかを判断することができます。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); dispatch_async(queue, ^ { NSLog(@"dispatch_semaphore_wait - 1"); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"start long task dummy"); sleep(10); NSLog(@"end long task dummy"); NSLog(@"dispatch_semaphore_signal - 1"); dispatch_semaphore_signal(semaphore); }); sleep(3); dispatch_async(queue, ^ { NSLog(@"dispatch_semaphore_wait - 2"); dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_USEC); long result = dispatch_semaphore_wait(semaphore, time); if (result == 0) { NSLog(@"dispatch_semaphore_wait wait success"); } else { NSLog(@"dispatch_semaphore_wait time out"); } NSLog(@"dispatch_semaphore_signal - 2"); dispatch_semaphore_signal(semaphore); });
2017-08-27 00:52:23.344 Sunaba[69701:6121419] dispatch_semaphore_wait - 1 2017-08-27 00:52:23.344 Sunaba[69701:6121419] start long task dummy 2017-08-27 00:52:26.345 Sunaba[69701:6121422] dispatch_semaphore_wait - 2 2017-08-27 00:52:26.345 Sunaba[69701:6121422] dispatch_semaphore_wait time out 2017-08-27 00:52:26.346 Sunaba[69701:6121422] dispatch_semaphore_signal - 2 2017-08-27 00:52:33.348 Sunaba[69701:6121419] end long task dummy 2017-08-27 00:52:33.349 Sunaba[69701:6121419] dispatch_semaphore_signal - 1
現場からは以上です。
エキスパートObjective-Cプログラミング ?iOS/OS Xのメモリ管理とマルチスレッド?
- 作者: 坂本一樹
- 出版社/メーカー: インプレス
- 発売日: 2011/11/18
- メディア: 単行本(ソフトカバー)
- 購入: 8人 クリック: 343回
- この商品を含むブログ (25件) を見る