2009-12-10[木] C標準ライブラリのマルチスレッド対応のメモグローバル変数や関数内部のstatic変数、あるいはそれらにアクセスする関数は、 複数のスレッドから同時に読み書きが行われると破綻する(バグになる). C標準ライブラリで(特にマルチスレッドセーフに作っていない場合)そのようなものは
等結構ある.(malloc関係はちょっと別枠だけど)
マルチスレッド対応の方法としては、たとえば元が static unsigned long rand_seed = 1; int rand(void) { rand_seed = rand_seed * 1103515245L + 12345; return (rand_seed >> 16) & 0x7fff; } て感じだとすると, 雰囲気として
struct ThreadLocalVar { // この構造体は適当 long rand_seed; // rand,srand char* strtok_ptr; // strtok char tmpnam_buf[_MAX_PATH]; // tmpnam int errno_wk; // errno : (その他標準ライブラリが使う変数全部) : }; ThreadLocalVar* get_threadLocalVar() { return 現在のスレッドのThreadLocalへのポインタを返す; } int rand(void) { ThreadLocalVar* p = get_threadLocalVar(); p->rand_seed = p->rand_seed * 1103515245L + 12345; return (p->rand_seed >> 16) & 0x7fff; } といった感じに、ライブラリが内部で使う変数すべてを収めた構造体を用意してスレッド別にそのメモリを持つ. スレッドごとに独立して処理するため、他スレッドの影響が起きないようになる.
当然、スレッドの開始時にはこの構造体の初期化が必要になる.
あと、上記では、適当にget_threadLocalVar()の名で中身はしょってるけど、
vcだと_getptd()、 ようは、スレッド別のメモリのポインタの取得は、 グローバル変数アクセスごとにmutex等で制御したりするのに比べれば まま軽いだろう(そこまで非効率な実装にはなってなかったよと).
ただ strtok のような本来十分に軽い処理からすれば
(そうであることを前提に利用頻度が高い場合)、
スレッド別のメモリのポインタの取得は気になるかもで、
可能なら使わずにすます形にしていったほうがよいだろう.
C++0xではスレッドローカル記憶域(TLS)が追加されるかもらしい.
そういやD言語ver2もサポートしてる. D2の場合は特に指定のないグローバル変数はスレッドローカルになる. |