woshidan's loose leaf

ぼんやり勉強しています

とりあえず今日はセマフォを使ってみたい

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のメモリ管理とマルチスレッド?

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

*1:そしてJavaでもセマフォとかその辺の話はあり、Java並行処理プログラミング積んでてすまんな… って感じ