为什么 Darwin 的 strtod 线程不安全?
以下测试总是在我的 Intel Mac Mini 上产生故障或总线错误。
编译器:
uname -a:
Darwin vogon13 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:55:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_I386 i386
g++ -v:
Target: i686-apple-darwin9
Configured with: /var/tmp/gcc/gcc-5493~1/src/configure
--disable-checking -enable-werror --prefix=/usr --mandir=/share/man
--enable-languages=c,objc,c++,obj-c++
--program-transform-name=/^[cg][^.-]*$/s/$/-4.0/
--with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib
--build=i686-apple-darwin9 --with-arch=apple --with-tune=generic
--host=i686-apple-darwin9 --target=i686-apple-darwin9
Thread model: posix
gcc version 4.0.1 (Apple Inc. build 5493)
编译命令:
"g++" -ftemplate-depth-128 -O3 -finline-functions -Wno-inline -Wall
-pedantic -g -no-cpp-precomp -gdwarf-2 -Wno-long-double -Wno-long-long -fPIC
-DBOOST_DATE_TIME_NO_LIB=1 -DBOOST_THREAD_NO_LIB=1 -DBOOST_THREAD_USE_LIB=1
-DDATE_TIME_INLINE -DNDEBUG -I"." -c -o "strtod_test.o" "strtod_test.cpp"
"g++" -o "strtod_test" "strtod_test.o"
"libboost_thread-xgcc40-mt-s.a" "libboost_date_time-xgcc40-mt-s.a"
-g -nodefaultlibs -shared-libgcc -lstdc++-static -lgcc_eh -lgcc -lSystem
-Wl,-dead_strip -no_dead_strip_inits_and_terms -fPIC
源代码:
#include "boost/thread/thread.hpp"
#include "boost/thread/barrier.hpp"
#include <iostream>
using namespace std;
void testThreadSafetyWorker(boost::barrier* testBarrier)
{
testBarrier->wait(); // wait until all threads have started
try
{
const char* str = "1234.5678";
const char* end = str;
double result = strtod(str, const_cast<char**>(&end));
if (fabs(result-1234.5678) > 1e-6)
throw runtime_error("result is wrong!");
}
catch (exception& e) {cerr << "Exception in worker thread: " << e.what() << endl;}
catch (...) {cerr << "Unhandled exception in worker thread." << endl;}
}
void testThreadSafety(const int& testThreadCount)
{
boost::barrier testBarrier(testThreadCount);
boost::thread_group testThreadGroup;
for (int i=0; i < testThreadCount; ++i)
testThreadGroup.add_thread(new boost::thread(&testThreadSafetyWorker, &testBarrier));
testThreadGroup.join_all();
}
int main(int argc, char* argv[])
{
try
{
testThreadSafety(2);
testThreadSafety(4);
testThreadSafety(8);
testThreadSafety(16);
return 0;
}
catch (exception& e) {cerr << e.what() << endl;}
catch (...) {cerr << "Unhandled exception in main thread." << endl;}
return 1;
}
堆栈跟踪:
(gdb) bt
#0 0x950c8f30 in strlen ()
#1 0x9518c16d in strtod_l$UNIX2003 ()
#2 0x9518d2e0 in strtod$UNIX2003 ()
#3 0x00001950 in testThreadSafetyWorker (testBarrier=0xbffff850) at strtod_test.cpp:21
#4 0x0000545d in thread_proxy (param=0xffffffff) at boost_1_43_0/libs/thread/src/pthread/thread.cpp:12? ?1
#5 0x950f1155 in _pthread_start () #6 0x950f1012 in thread_start ()
The following test always produces failures or bus errors for me on my Intel Mac Mini.
Compiler:
uname -a:
Darwin vogon13 9.8.0 Darwin Kernel Version 9.8.0: Wed Jul 15 16:55:01 PDT 2009; root:xnu-1228.15.4~1/RELEASE_I386 i386
g++ -v:
Target: i686-apple-darwin9
Configured with: /var/tmp/gcc/gcc-5493~1/src/configure
--disable-checking -enable-werror --prefix=/usr --mandir=/share/man
--enable-languages=c,objc,c++,obj-c++
--program-transform-name=/^[cg][^.-]*$/s/$/-4.0/
--with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib
--build=i686-apple-darwin9 --with-arch=apple --with-tune=generic
--host=i686-apple-darwin9 --target=i686-apple-darwin9
Thread model: posix
gcc version 4.0.1 (Apple Inc. build 5493)
Compile commands:
"g++" -ftemplate-depth-128 -O3 -finline-functions -Wno-inline -Wall
-pedantic -g -no-cpp-precomp -gdwarf-2 -Wno-long-double -Wno-long-long -fPIC
-DBOOST_DATE_TIME_NO_LIB=1 -DBOOST_THREAD_NO_LIB=1 -DBOOST_THREAD_USE_LIB=1
-DDATE_TIME_INLINE -DNDEBUG -I"." -c -o "strtod_test.o" "strtod_test.cpp"
"g++" -o "strtod_test" "strtod_test.o"
"libboost_thread-xgcc40-mt-s.a" "libboost_date_time-xgcc40-mt-s.a"
-g -nodefaultlibs -shared-libgcc -lstdc++-static -lgcc_eh -lgcc -lSystem
-Wl,-dead_strip -no_dead_strip_inits_and_terms -fPIC
Source code:
#include "boost/thread/thread.hpp"
#include "boost/thread/barrier.hpp"
#include <iostream>
using namespace std;
void testThreadSafetyWorker(boost::barrier* testBarrier)
{
testBarrier->wait(); // wait until all threads have started
try
{
const char* str = "1234.5678";
const char* end = str;
double result = strtod(str, const_cast<char**>(&end));
if (fabs(result-1234.5678) > 1e-6)
throw runtime_error("result is wrong!");
}
catch (exception& e) {cerr << "Exception in worker thread: " << e.what() << endl;}
catch (...) {cerr << "Unhandled exception in worker thread." << endl;}
}
void testThreadSafety(const int& testThreadCount)
{
boost::barrier testBarrier(testThreadCount);
boost::thread_group testThreadGroup;
for (int i=0; i < testThreadCount; ++i)
testThreadGroup.add_thread(new boost::thread(&testThreadSafetyWorker, &testBarrier));
testThreadGroup.join_all();
}
int main(int argc, char* argv[])
{
try
{
testThreadSafety(2);
testThreadSafety(4);
testThreadSafety(8);
testThreadSafety(16);
return 0;
}
catch (exception& e) {cerr << e.what() << endl;}
catch (...) {cerr << "Unhandled exception in main thread." << endl;}
return 1;
}
Stack trace:
(gdb) bt
#0 0x950c8f30 in strlen ()
#1 0x9518c16d in strtod_l$UNIX2003 ()
#2 0x9518d2e0 in strtod$UNIX2003 ()
#3 0x00001950 in testThreadSafetyWorker (testBarrier=0xbffff850) at strtod_test.cpp:21
#4 0x0000545d in thread_proxy (param=0xffffffff) at boost_1_43_0/libs/thread/src/pthread/thread.cpp:12? ?1
#5 0x950f1155 in _pthread_start () #6 0x950f1012 in thread_start ()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
strtod 不是线程安全的。在任何规范中都从未声明过它是线程安全的。您应该使用 strtod_l,它需要一个区域设置。很可能有一个共享数据结构由于在线程代码中的使用而被破坏。
strtod is not thread safe. It's never been stated in any specs that it was thread-safe. You should be using strtod_l, which takes a locale. In all likelehood there is a shared data structure that is being clobbered by it's use in the threaded code.