Objective-C @synchronized GCDメモ

ふと気になったので実験してみた。
Objective-Cの@synchronizedは、つまりはmutexらしい。
Appleのドキュメントに書いてあった。
例えば、

@implementation Singleton
@synthesize count;

static Singleton* singleton = nil;  

+ (id)sharedObject{
    if (!singleton) {
        singleton = [[Singleton alloc]init];
        singleton.count = 0;
    }
    return singleton;
}

- (void)increment{
    count ++;
    NSLog(@"%d",count);
}
@end

こんな感じでシングルトンなオブジェクトを用意して、incrementをGCD使って10万回呼んでみた。

    Singleton *singleton = [Singleton sharedObject];
    dispatch_queue_t cQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    for (NSInteger i=0; i<100000;i++) {
        dispatch_async(cQueue, ^{
            [singleton increment];
        });
    }

すると、

...
2012-01-29 20:14:28.755 ConcurrentTest[1088:48303] 99826
2012-01-29 20:14:28.804 ConcurrentTest[1088:31303] 99902
2012-01-29 20:14:28.803 ConcurrentTest[1088:2b503] 99901
2012-01-29 20:14:28.778 ConcurrentTest[1088:43803] 99852
2012-01-29 20:14:28.808 ConcurrentTest[1088:42a03] 99936
2012-01-29 20:14:28.802 ConcurrentTest[1088:36303] 99888
2012-01-29 20:14:28.806 ConcurrentTest[1088:35d03] 99919
2012-01-29 20:14:28.779 ConcurrentTest[1088:45603] 99883
2012-01-29 20:14:28.735 ConcurrentTest[1088:2e703] 99824

順番が前後しているのはともかく、10万まで値がインクリメントされなかった。
そこで、インクリメントしている部分を@synchronizedで囲ってやった

- (void)increment{
    @synchronized(self) {  
        count ++;
    }
    NSLog(@"%d",count);
}

すると、

2012-01-29 20:17:44.913 ConcurrentTest[1110:3eb03] 99996
2012-01-29 20:17:44.913 ConcurrentTest[1110:2f603] 99997
2012-01-29 20:17:44.815 ConcurrentTest[1110:18703] 99916
2012-01-29 20:17:44.913 ConcurrentTest[1110:49703] 100000
2012-01-29 20:17:44.913 ConcurrentTest[1110:28303] 99999
2012-01-29 20:17:44.913 ConcurrentTest[1110:44f03] 99985
2012-01-29 20:17:44.913 ConcurrentTest[1110:2c803] 99984
2012-01-29 20:17:44.912 ConcurrentTest[1110:4e103] 99967
2012-01-29 20:17:44.913 ConcurrentTest[1110:44903] 99992
2012-01-29 20:17:44.913 ConcurrentTest[1110:49903] 99971
2012-01-29 20:17:44.912 ConcurrentTest[1110:3ed03] 99947
2012-01-29 20:17:44.912 ConcurrentTest[1110:3bd03] 99949
2012-01-29 20:17:44.814 ConcurrentTest[1110:27703] 99907
|

きちんと10万までカウントされている。
もちろんパフォーマンスは落ちる。

dispatch_queue_t cQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

は並列キューなので、シリアルキューに入れてあげてもよい。

dispatch_queue_t sQueue = dispatch_queue_create("com.hogefuga", NULL);

2012-01-29 21:45:35.741 ConcurrentTest[1465:11503] 9994
2012-01-29 21:45:35.741 ConcurrentTest[1465:11503] 9995
2012-01-29 21:45:35.742 ConcurrentTest[1465:11503] 9996
2012-01-29 21:45:35.742 ConcurrentTest[1465:11503] 9997
2012-01-29 21:45:35.743 ConcurrentTest[1465:11503] 9998
2012-01-29 21:45:35.744 ConcurrentTest[1465:11503] 9999
2012-01-29 21:45:35.744 ConcurrentTest[1465:11503] 10000

順番もそろっている。