周五开会做团队成员codereivew, 有同事提出了一个关于gmtime多线程是否安全的问题, 当时觉得程序Link了VC的多线程库,应该不是问题。还好回头核实了一下,发现了竟是一个潜在的bug。
程序分在application(完成项目特定功能)和framework(可重用的核心功能)两部分,线程的启动由framework完成。 app中使用了gmtime/localtime等C库函数。
gmtime/localtime等C函数是非线程安全的,这个n年前就知道, 也知道在Windows平台上VC有MT版本的runtime library,通过线程的局部存储(TLS)实现了/mt 链接时的线程安全。 然而线程的启动必须通过C运行时库的_beginthreadex, 而不是win32 API CreateThead 。不幸的的是当年framework的实现者貌似不清楚_beginthreadex与CreateThread的区别(BTW, 这个是当年进入第一家公司的一道面试题,所以印象颇为深刻),直接调CreateThread启动了线程。
解决方案调查中,VC CRT竟是没有gmtime_r/localtime_r。
参考资料:
http://social.msdn.microsoft.com/forums/en-US/vclanguage/thread/c727ae29-5a7a-42b6-ad0b-f6b21c1180b2
http://www.tech-archive.net/Archive/VC/microsoft.public.vc.language/2006-02/msg00013.html
Update on April.27
当线程由CreateThread启动并调用了gmtime/localtime之类的函数时, CRT会发现应该有的TLS(created by _beginthread)为空,所以创建一个的TLS存储区域; 线程退出时该TLS区域不会被释放,所以会有memory leak。 然而回归本例,在我们的框架下线程不会动态创建,所以leak不是大问题,准备鸵鸟一下。。。