woshidan's loose leaf

ぼんやり勉強しています

GCDでちょっと遊ぶ

バックグラウンドスレッドに非同期で実行したい処理を投げる

memo

    dispatch_async(タスクを入れるキュー, ^{
        // タスクの処理内容を表すブロック
    });

    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(globalQueue, ^{
        sleep(10);
        NSLog(@"thread label %s", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
    });
    NSLog(@"thread label %s", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
2017-08-24 22:15:24.552 TestApp[56964:5152615] thread label com.apple.main-thread
2017-08-24 22:15:34.556 TestApp[56964:5152686] thread label com.apple.root.default-qos

バックグラウンドスレッドに同期実行したい処理を投げる

memo

    dispatch_sync(タスクを入れるキュー, ^{
        // タスクの処理内容を表すブロック
    });

    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_sync(globalQueue, ^{
        sleep(10);
        NSLog(@"thread label %s", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
    });
    NSLog(@"thread label %s", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
2017-08-24 22:18:05.450 TestApp[57017:5156204] thread label com.apple.root.default-qos
2017-08-24 22:18:05.450 TestApp[57017:5156204] thread label com.apple.main-thread

タスクを並行に実行させる

memo

// 2つ目の引数でConcurrentキュー を生成するぞ、という指定
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.exmaple.gcd.MyConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);

Concurrentキュー を利用する。

dispatch_queue_t concurrentQueue = dispatch_queue_create("com.exmaple.gcd.MyConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 10; i++) {
    dispatch_async(cuncurrentQueue, ^{
        sleep(rand() % 10 + 1);
        NSLog(@"thread label %s - %i", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), i);
    });
}
2017-08-24 22:30:49.667 TestApp[57252:5175489] thread label com.exmaple.gcd.MyConcurrentDispatchQueue - 5
2017-08-24 22:30:51.667 TestApp[57252:5175490] thread label com.exmaple.gcd.MyConcurrentDispatchQueue - 6
2017-08-24 22:30:52.664 TestApp[57252:5175276] thread label com.exmaple.gcd.MyConcurrentDispatchQueue - 3
2017-08-24 22:30:52.664 TestApp[57252:5175494] thread label com.exmaple.gcd.MyConcurrentDispatchQueue - 9
2017-08-24 22:30:53.667 TestApp[57252:5175491] thread label com.exmaple.gcd.MyConcurrentDispatchQueue - 7
2017-08-24 22:30:56.667 TestApp[57252:5175269] thread label com.exmaple.gcd.MyConcurrentDispatchQueue - 1
2017-08-24 22:30:56.667 TestApp[57252:5175267] thread label com.exmaple.gcd.MyConcurrentDispatchQueue - 0
2017-08-24 22:30:57.667 TestApp[57252:5175488] thread label com.exmaple.gcd.MyConcurrentDispatchQueue - 4
2017-08-24 22:30:57.667 TestApp[57252:5175493] thread label com.exmaple.gcd.MyConcurrentDispatchQueue - 8
2017-08-24 22:30:58.662 TestApp[57252:5175271] thread label com.exmaple.gcd.MyConcurrentDispatchQueue - 2

タスクを直列に実行させる

memo

// 2つ目の引数でSerialキュー を生成するぞ、という指定
dispatch_queue_t serialQueue = dispatch_queue_create("com.exmaple.gcd.MySerialDispatchQueue", DISPATCH_QUEUE_SERIAL);

// DISPATCH_QUEUE_SERIAL は NULL.
/*!
 * @const DISPATCH_QUEUE_SERIAL
 *
 * @discussion A dispatch queue that invokes blocks serially in FIFO order.
 */
#define DISPATCH_QUEUE_SERIAL NULL

Serialキュー を利用する。

dispatch_queue_t serialQueue = dispatch_queue_create("com.exmaple.gcd.MySerialDispatchQueue", DISPATCH_QUEUE_SERIAL);
for (int i = 0; i < 10; i++) {
    dispatch_async(serialQueue, ^{
        sleep(rand() % 10 + 1);
        NSLog(@"thread label %s - %i", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), i);
    });
}
2017-08-24 22:37:00.679 TestApp[57358:5185254] thread label com.exmaple.gcd.MySerialDispatchQueue - 0
2017-08-24 22:37:10.679 TestApp[57358:5185254] thread label com.exmaple.gcd.MySerialDispatchQueue - 1
2017-08-24 22:37:14.684 TestApp[57358:5185254] thread label com.exmaple.gcd.MySerialDispatchQueue - 2
2017-08-24 22:37:23.685 TestApp[57358:5185254] thread label com.exmaple.gcd.MySerialDispatchQueue - 3
2017-08-24 22:37:24.689 TestApp[57358:5185254] thread label com.exmaple.gcd.MySerialDispatchQueue - 4
2017-08-24 22:37:27.693 TestApp[57358:5185254] thread label com.exmaple.gcd.MySerialDispatchQueue - 5
2017-08-24 22:37:32.696 TestApp[57358:5185254] thread label com.exmaple.gcd.MySerialDispatchQueue - 6
2017-08-24 22:37:41.700 TestApp[57358:5185254] thread label com.exmaple.gcd.MySerialDispatchQueue - 7
2017-08-24 22:37:45.702 TestApp[57358:5185254] thread label com.exmaple.gcd.MySerialDispatchQueue - 8
2017-08-24 22:37:55.706 TestApp[57358:5185254] thread label com.exmaple.gcd.MySerialDispatchQueue - 9

dispatch_get_global_queue と dispatch_queue_create の違い

  • dispatch_get_main_queue / dispatch_get_global_queue
    • システムが用意している既存のキューがいくつかあるのでそれを取得する。Main Dispatch Queue以外はConcurrentキュー
  • dispatch_queue_create
    • 自作のキュー。二つ目の引数でConcurrent/Serialキューのどちらかを決める

指定した時間の後に処理を実行したい

Handler#postDelay 的な。

memo

  • dispatch_time_t
  • dispath_after

の二つを使う。

書き方

   dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC);
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_after(time, globalQueue, ^{
        NSLog(@"thread label %s", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
    });
    NSLog(@"thread label %s", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
2017-08-24 22:55:03.519 TestApp[57464:5205849] thread label com.apple.main-thread
2017-08-24 22:55:08.519 TestApp[57464:5205963] thread label com.apple.root.default-qos

全てのキューの処理が終わったら任意の処理を行う

memo

  • dispatch_group_t
  • dispatch_group_async
  • dispatch_group_wait

の3つを使う。あまり書いたことないですがやりたいことはjoinに近い?

書き方

    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_t another_group = dispatch_group_create();
    
    dispatch_group_async(another_group, globalQueue, ^{
        NSLog(@"thread label %s - task 1 start", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
        sleep(rand() % 10 + 15);
        NSLog(@"thread label %s - task 1 end", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
    });
    
    dispatch_group_async(group, globalQueue, ^{
        NSLog(@"thread label %s - task 2 start", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
        sleep(rand() % 10 + 1);
        NSLog(@"thread label %s - task 2 end", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
    });
    
    dispatch_group_async(group, globalQueue, ^{
        NSLog(@"thread label %s - task 3 start", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
        sleep(rand() % 10 + 1);
        NSLog(@"thread label %s - task 3 end", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
    });
    
    dispatch_group_async(group, globalQueue, ^{
        NSLog(@"thread label %s - task 4 start", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
        sleep(rand() % 10 + 1);
        NSLog(@"thread label %s - task 4 end", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
    });
    
    NSLog(@"before dispatch_group_wait - group");
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    NSLog(@"after dispatch_group_wait - group");
    
    NSLog(@"before dispatch_group_wait - another_group");
    dispatch_group_wait(another_group, DISPATCH_TIME_FOREVER);
    NSLog(@"after dispatch_group_wait - another_group");
    
    NSLog(@"thread label %s", dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL));
2017-08-24 23:03:42.995 TestApp[57690:5218146] thread label com.apple.root.default-qos - task 1 start
2017-08-24 23:03:42.995 TestApp[57690:5218151] thread label com.apple.root.default-qos - task 2 start
2017-08-24 23:03:42.995 TestApp[57690:5218143] thread label com.apple.root.default-qos - task 3 start
2017-08-24 23:03:42.995 TestApp[57690:5218149] thread label com.apple.root.default-qos - task 4 start
2017-08-24 23:03:42.995 TestApp[57690:5218087] before dispatch_group_wait - group
2017-08-24 23:03:47.000 TestApp[57690:5218143] thread label com.apple.root.default-qos - task 3 end
2017-08-24 23:03:51.997 TestApp[57690:5218149] thread label com.apple.root.default-qos - task 4 end
2017-08-24 23:03:52.997 TestApp[57690:5218151] thread label com.apple.root.default-qos - task 2 end
2017-08-24 23:03:52.998 TestApp[57690:5218087] after dispatch_group_wait - group // groupのキューに追加した task 3, 4, 2を待つ

2017-08-24 23:03:52.998 TestApp[57690:5218087] before dispatch_group_wait - another_group
2017-08-24 23:04:04.997 TestApp[57690:5218146] thread label com.apple.root.default-qos - task 1 end
2017-08-24 23:04:04.997 TestApp[57690:5218087] after dispatch_group_wait - another_group // another_groupのキューに追加した task 1を待つ

2017-08-24 23:04:04.998 TestApp[57690:5218087] thread label com.apple.main-thread

セマフォについてはまた明日。。

参考

エキスパートObjective-Cプログラミング ?iOS/OS Xのメモリ管理とマルチスレッド?

エキスパートObjective-Cプログラミング ?iOS/OS Xのメモリ管理とマルチスレッド?