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