GCDマルチスレッドの使用(四)

15551 ワード

dispatch_についてset_target_queueとdispatch_afterの使用.
GCDの関数dispatch_を使用queue_createによって作成されたDispatch Queue(Serial Dispatch QueueおよびConcurrent Dispatch Queue)で使用される優先度はいずれもデフォルトの優先度であり、必要に応じて優先度が変更される場合があります.優先度を変更するにはdispatch_set_target_queue関数を使用します.以下に、優先度の低いSerial Dispatch Queueを作成する例を示します.
/**
 *           Serial Dispatch Queue
 */
- (void)createLowPrioritySerialDispatchQueue {
    dispatch_queue_t queue = dispatch_queue_create("com.hxp.queue", DISPATCH_QUEUE_SERIAL);  //            
    dispatch_queue_t targetQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); //           Global Dispatch Queue
    dispatch_set_target_queue(queue, targetQueue);  //        Dispatch Queue    
}

        dispatch_set_target_Queue関数の1番目のパラメータは優先度を変更する必要があるDispatch Queueであり、2番目のパラメータは使用する実行優先度が同じ優先度を指定するGlobal Dispatch Queue、すなわちターゲットDispatch Queueである.
また、dispatch_set_target_Queue関数には、実行順序を指定する機能もあります.まず、コードと出力結果を見てみましょう.
    dispatch_queue_t queue0 = dispatch_queue_create("com.hxp.queue0", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue1 = dispatch_queue_create("com.hxp.queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("com.hxp.queue2", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue3 = dispatch_queue_create("com.hxp.queue3", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue4 = dispatch_queue_create("com.hxp.queue4", DISPATCH_QUEUE_SERIAL);
    
    
    dispatch_async(queue0, ^{
        NSLog(@"%@:queue0", [NSThread currentThread]);
    });
    dispatch_async(queue1, ^{
        NSLog(@"%@:queue1", [NSThread currentThread]);
    });
    dispatch_async(queue2, ^{
        NSLog(@"%@:queue2", [NSThread currentThread]);
    });
    dispatch_async(queue3, ^{
        NSLog(@"%@:queue3", [NSThread currentThread]);
    });
    dispatch_async(queue4, ^{
        NSLog(@"%@:queue4", [NSThread currentThread]);
    });

通常の出力結果は、順序が乱雑で、同時に実行されるべきです.
2015-06-19 07:01:12.885 GCD_Study[23054:3603] {name = (null), num = 6}:queue4
2015-06-19 07:01:12.885 GCD_Study[23054:1303] {name = (null), num = 2}:queue0
2015-06-19 07:01:12.885 GCD_Study[23054:3403] {name = (null), num = 5}:queue2
2015-06-19 07:01:12.885 GCD_Study[23054:3503] {name = (null), num = 3}:queue3
2015-06-19 07:01:12.885 GCD_Study[23054:3107] {name = (null), num = 4}:queue1

次にdispatch_を使用しますset_target_Queue関数の優先度を指定すると、次のようになります.
    dispatch_queue_t queue0 = dispatch_queue_create("com.hxp.queue0", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue1 = dispatch_queue_create("com.hxp.queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("com.hxp.queue2", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue3 = dispatch_queue_create("com.hxp.queue3", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue4 = dispatch_queue_create("com.hxp.queue4", DISPATCH_QUEUE_SERIAL);
    
    dispatch_set_target_queue(queue1, queue0);
    dispatch_set_target_queue(queue2, queue0);
    dispatch_set_target_queue(queue3, queue0);
    dispatch_set_target_queue(queue4, queue0);
    
    dispatch_async(queue0, ^{
        NSLog(@"%@:queue0", [NSThread currentThread]);
    });
    dispatch_async(queue1, ^{
        NSLog(@"%@:queue1", [NSThread currentThread]);
    });
    dispatch_async(queue2, ^{
        NSLog(@"%@:queue2", [NSThread currentThread]);
    });
    dispatch_async(queue3, ^{
        NSLog(@"%@:queue3", [NSThread currentThread]);
    });
    dispatch_async(queue4, ^{
        NSLog(@"%@:queue4", [NSThread currentThread]);
    });

今回はdispatch_を使ってset_target_Queue関数は、Serial Dispatch Queueのターゲットを指定し、結果を出力します.
2015-06-19 07:16:11.244 GCD_Study[23239:1303] {name = (null), num = 2}:queue0
2015-06-19 07:16:11.246 GCD_Study[23239:1303] {name = (null), num = 2}:queue1
2015-06-19 07:16:11.247 GCD_Study[23239:1303] {name = (null), num = 2}:queue2
2015-06-19 07:16:11.248 GCD_Study[23239:1303] {name = (null), num = 2}:queue3
2015-06-19 07:16:11.250 GCD_Study[23239:1303] {name = (null), num = 2}:queue4

並行して実行されていた複数のSerial Dispatch Queueがシリアル実行となる.並列に実行できない処理を複数のSerial Dispatch Queueに追加しなければならない場合、dispatch_set_target_Queue関数はターゲットをSerial Dispatch Queueとして指定し、処理の並列実行を防止します.
 
数秒後にアクションを実行したいというシーンを想像します.このようなシーンではdispatch_が必要ですafter関数です.次のコードは、2秒後に文字列を出力します.
- (void)dispatchAfter {
    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 2ull * NSEC_PER_SEC);
    dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"Now");
    dispatch_after(time, queue, ^{
        NSLog(@"after 2sec");
    });
}

出力結果:
2015-06-19 07:46:20.182 GCD_Study[23269:607] Now
2015-06-19 07:46:22.183 GCD_Study[23269:607] after 2sec

誤差はありましたが、2秒後くらいでした.なぜならdispatch_after関数は,指定した時間後に処理を実行するのではなく,指定した時間にDispatch Queueに処理を追加する.上のコードは、2秒後にタスクを実行するBlockをdispatch_asyncはMain Dispatch Queueに追加されます.
次はdispatch_after関数の3つのパラメータ.最初のパラメータは指定時間用のdispatch_time_dispatch_を使用したtタイプの値time関数またはdispatch_walltime関数を取得します.dispatch_time関数は、1番目のパラメータが指定した時間から、2番目のパラメータが指定したミリ秒単位の時間までの時間を取得します.上のコードの最初のパラメータ用DISPATCH_TIME_NOWは、これから2番目のパラメータが2 ull*NSEC_であることを示しています.PER_SECは、2秒の遅延を表し、合わせて今から2秒後にMain Dispatch QueueにBlockを追加します.
数値とNSEC_PER_SECの積はミリ秒単位の数値を得る.以下の値をとる
#define NSEC_PER_USEC    1000ull        /* nanoseconds per microsecond */
#define USEC_PER_SEC    1000000ull    /* microseconds per second */
#define NSEC_PER_SEC    1000000000ull    /* nanoseconds per second */
#define NSEC_PER_MSEC    1000000ull    /* nanoseconds per millisecond */

        NSEC_PER_USEC:1000ナノ秒/1マイクロ秒
        USEC_PER_SEC:1000000マイクロ秒/1秒
        NSEC_PER_SEC:10000000ナノ秒/1秒
        NSEC_PER_MSEC:1000000ナノ秒/1ミリ秒
ullはC言語における数値字面量であり、タイプを示す際に用いられる文字列を表示し、unsigned long longを表す.