Grand Central Dispatch その5 semaphore

ディスパッチはいままでの並列処理の方法と比べるとシンプルで簡単だ、なんて書かれていたりしますけど、どうやらセマフォは欠かせないようで、ディスパッチにもあります。

とりあえずサンプルコードから。

#include <stdio.h>
#include <unistd.h>
#include <dispatch/dispatch.h>
int main (int argc, const char * argv[]) {
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    
    for (int i = 0; i < 10; i++) {
        dispatch_group_async(group, queue, ^{
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            //クリティカルセクション開始
            printf("start %d\n", (int)i);
            usleep(10000);
            printf("end %d\n", (int)i);
            //クリティカルセクション終了
            dispatch_semaphore_signal(semaphore);
        });
    }
    
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    
    dispatch_release(semaphore);
    dispatch_release(group);
    
    return 0;
}

ディスパッチのセマフォの使い方としてはまず、dispatch_semaphore_createでセマフォのオブジェクトdispatch_semaphore_tを作ります。引数にはセマフォの旗の数を指定できます。0だと一回も進入できなくなってしまいますので1以上を指定します。

そして、クリティカルセクションをdispatch_semaphore_wait〜dispatch_semaphore_signalで囲みます。それぞれ引数にセマフォオブジェクトを渡します。waitでは進入できない時に待つ時間を指定できて、DISPATCH_TIME_FOREVERなら永久に待ちます。

サンプルコードを実行すると、クリティカルセクション開始〜終了としているところは同時に実行されず、printfでstartとendがセットで0から9まで順番に出力されます。もし、セマフォ関連の関数を排除したら、startのあとにスリープさせていますので、startが10個出力された後に、endが10個出力されるはずです。

という感じで、ディスパッチのキューに直接ブロックを渡す関係は以上で終わりです。ちなみに、キューにブロックを渡してしまうと後からキャンセルが出来なかったりしますのでご注意を。

その処理のキャンセルとかも含めて、ディスパッチにはソースという仕組みも用意されていますので、次回以降見ていこうと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です