「__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修飾子に関しては、以上で終りです。補遺はまだ続くかもしれません。