NSOperationQueueを使って非同期の処理を同期的に扱ってみる

NSOperationQueueを使って非同期の処理を同期的に扱ってみる最近、ブログあまり書いてなくてまずいです。Swift書きたいです。でも明日の準備としてちょっとだけ調べてみたというか、以前、やったものを取り出して書いておこうと思います。

NSOperationQueueを利用して処理を直列化し、更に、1つ1つのオペレーション内で処理が終わったことを確認した上で次の処理に移るという方法です。オペレーション内で何か処理を行って、その終了を待って次のオペレーションを行うというのは、NSOperationをサブクラス化するなど他の方法もあるのですが、面倒なのでもっと簡単な方法はないかなと思って下記の方法を思いつきました。

書いてみた

NSLog(@"start");
self.queue = [[NSOperationQueue alloc] init];
self.queue.maxConcurrentOperationCount = 1;
for (int i = 0; i < 10; i++) {
    [self.queue addOperationWithBlock:^{
        
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            u_int32_t t = arc4random_uniform(4);
            sleep(t);
            NSLog(@"%d",i);
            dispatch_semaphore_signal(semaphore);
        });
        NSLog(@"wait...");
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    }];
}

説明

self.queueはNSOperationQueueのインスタンスです。今回はUIViewControllerが保持してます。maxConcurrentOperationで一度に行う処理を1つだけにします。addOperationWithBlock:はブロックでオペレーションを追加できるようにするメソッドです。dispatch_asyncを行っているのは非同期を表現するためです。

maxConcurrentOperationを一つにして書いたもの

NSLog(@"start");
self.queue = [[NSOperationQueue alloc] init];
self.queue.maxConcurrentOperationCount = 1;
for (int i = 0; i < 10; i++) {
    [self.queue addOperationWithBlock:^{
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            u_int32_t t = arc4random_uniform(4);
            sleep(t);
            NSLog(@"%d",i);
        });
    }];
}

これだけでも良い気もするのですが、非同期なので、すぐにオペレーションの終了を待たずに次のオペレーションに移ってしまいます。1つまえの処理が終わってから次の処理を行うというようにしたいので、今回は処理をdispatch_semaphoereで囲むことにより、終了を確認した上で次の処理が行われるようにしました。こうすることで、dispatch_semaphore_signalが呼ばれるまではブロック内のdispatch_semaphore_waitで処理が止まっているので次のオペレーションに進みません。

おかしなところご指摘いただけるとありがたいです!

参考

Pocket
LINEで送る

You may also like...