localtimeやstrtokは本当にスレッドセーフにできないのか (3): GCC __thread keyword
3.3以降のgccを使っているのであれば、pthread_getspecific関数を使うのと同様のことを、特殊なキーワード __thread を使って実現できます。上で示したlocaltime関数の、長ったらしいソースコードは、次のように簡潔に書き直せます。
#include <time.h> #include <stdlib.h> struct tm* localtime(const time_t* timep) { static __thread struct tm ret; return localtime_r(timep, &ret); }
このコードを gcc -S -fverbose-asm してみると、pthread_key と pthread_once を使った上のソースコードより簡潔なコードが吐かれております。移植性を気にしないなら、可読性・速度ともにこちらの方法が勝っているとおもいます。
ちなみに、どれくらい簡潔かというと…次の通り。手元の環境では、素のlocaltimeに比べて、速度の低下は10%〜20%程度に抑えられました。これなら使えるかも。
localtime: pushl %ebp movl %esp, %ebp pushl %ebx call .L2 .L2: popl %ebx addl $_GLOBAL_OFFSET_TABLE_+[.-.L2], %ebx subl $12, %esp leal ret.0@TLSGD(,%ebx,1), %eax call ___tls_get_addr@PLT pushl %eax pushl 8(%ebp) call localtime_r@PLT movl -4(%ebp), %ebx leave ret
実行結果も、次のように特に問題ありません。
$ gcc -D_REENTRANT -O2 -fPIC -Wall -W -c localtime2.c $ gcc -shared -Wl,-soname,libtsf.so.1 -o libtsf.so.1.0.2 localtime2.o -lpthread $ LD_PRELOAD=./libtsf.so.1.0.2 ./a.out main thread ID = 4143980736 Thread ID 4143975344, return address is 0xf7000b70, result = Thu Sep 9 20:55:13 2004 Thread ID 4143975344, return address is 0xf7000b70, result = Thu Sep 9 20:55:13 2004 Thread ID 4133481392, return address is 0xf65feb70, result = Thu Sep 9 20:55:13 2004 Thread ID 4133481392, return address is 0xf65feb70, result = Thu Sep 9 20:55:13 2004 thread1 ID = 4143975344 thread2 ID = 4133481392 Thread ID 4143980736, return address is 0xf7002080, result = Thu Sep 9 20:55:13 2004 Thread ID 4143980736, return address is 0xf7002080, result = Thu Sep 9 20:55:13 2004
参考:
http://lucille.sourceforge.net/blog/archives/000308.html
http://docs.sun.com/db/doc/817-4912/6mkdg5432?l=ja&a=view