2011-01-31

『iOS 4プログラミングブック』 第5章マルチスレッド 補遺 その5

そろそろ皆様のお手元にもあるのではないかと思ったりしております。『iOS 4プログラミングブック』。

__block変数の書き換えは、スレッドセーフではない

さて、マルチスレッド下で安全に__block変数を書き換える方法とは。

そもそもマルチスレッドにするためにGCDのGlobal Queueを使ってるわけですから、やはりここはDispatch Semaphoreを使っておきましょう。詳しくはワシの226ページに書いてあーる。


#import <dispatch/dispatch.h>
#import <stdio.h>

int main()
{
__block int total = 0;

dispatch_semaphore_t sema = dispatch_semaphore_create(1);
dispatch_queue_t queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(10000, queue, ^(size_t index) {

dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

++total;

dispatch_semaphore_signal(sema);

});
dispatch_release(sema);

printf("total=%d\n", total);

return 0;
}


ふつうにセマフォです。


あと、今回の場合、Atomic operationsが使えます。

http://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man3/atomic.3.html


#import <libkern/OSAtomic.h>



dispatch_apply(10000, queue, ^(size_t index) {

OSAtomicIncrement32(&total);

});


Barrierあり/なしの使い分けは、http://stackoverflow.com/questions/2436513/macosx-osatomic-vs-osatomicbarrierにありました。


もしくはGCC組み込みAtomic関数(http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html)を使うのも手です。


dispatch_apply(10000, queue, ^(size_t index) {

__sync_fetch_and_add(&total, 1);

});


clangでも使えます。Mac OS X、iOS以外の環境でも使える点がメリットでしょうか。また上記のとおり、OSAtomicに対して若干汎用的すぎるところがデメリットと言えるかと(++がないとか)。移植性を取るかどうか、てことですね。GCC拡張使って移植性どうこう言うのもあれだとは思いますが。

てことで、__block修飾子に関しては、以上で終りです。補遺はまだ続くかもしれません。