【问题标题】:Why isn't Darwin's strtod thread safe?为什么达尔文的 strtod 线程不安全?
【发布时间】:2011-09-25 12:35:02
【问题描述】:

以下测试在我的 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 ()

【问题讨论】:

  • 您的代码对我来说很好用(一旦我在testThreadSafetyWorker 中的catch (exception&amp; e) {... 行中添加了一个右大括号)。当您遇到故障/总线错误时,gdb 中的回溯是什么样的?
  • @Adam Rosenfield:感谢您对遗漏支架的说明,我已修复它。我假设您正在测试某个版本的达尔文:哪一个?如果没有,我知道其他平台可以正常工作,包括 POSIX 和 MSVC。查看堆栈跟踪的更新问题。
  • GCC 4.0.1 可以追溯到 2005 年 7 月 7 日。那是 七年前。仅供参考。
  • 我不认为strtod 应该是线程安全的。一些实现明确声称它是线程安全的(例如 MKS Toolkit),但我找不到 glibc 的证据。为什么会这样?
  • POSIX 要求任何未明确记录为非线程安全的函数都是线程安全的。参见 IEEE 标准 1003.1-2008,XSH 2.9.1。

标签: c++ macos thread-safety darwin strtod


【解决方案1】:

strtod 不是线程安全的。 in any specs 从来没有说过它是线程安全的。您应该使用 strtod_l,它采用语言环境。很可能有一个共享数据结构正在被线程代码中的使用所破坏。

locale_t c_locale = newlocale (LC_ALL_MASK, "C", 0);
r = strtod_l(nptr, endptr, c_locale);
freelocale (c_locale);

【讨论】:

  • 我实际上是通过使用 lexical_cast 导致了这个错误,而后者又使用了 C++ 流,而后者又使用了 strtod(至少在 Darwin 上)。所以显然我不是唯一一个认为它应该是线程安全的人!我知道它不能保证是线程安全的,但究竟为什么不能。 :( 为每个调用创建一个语言环境?lexical_cast 还不够慢吗?;) 那么在这种情况下,使用 lexical_cast 或 C++ 流的人会做什么?
  • @Matt Chambers:使用现代编译器? strtod 是编译器的一部分。
  • strtod 是 glibc、IIRC 的一部分。前段时间对库进行了修复,以确保它是线程安全的。也许这不在图书馆的达尔文副本中。
  • @MSalters,@Tomalak Geret'kal:我升级到 llvm-gcc42,问题仍然存在。那是 MacPorts 提供的最新的 Darwin 编译器。接下来我将尝试香草 GCC 4.4。有趣的是,微软的非现代编译器如何做到这一点,但苹果的...
  • strtod 是线程安全的,或者至少 posix 要求它是线程安全的。如果它在 Darwin 上不是线程安全的,那就是(又一个)损坏操作系统中的一致性错误......
猜你喜欢
  • 1970-01-01
  • 2010-11-02
  • 2012-11-20
  • 2013-10-11
  • 2020-10-10
  • 1970-01-01
  • 2016-08-14
  • 2023-03-12
  • 1970-01-01
相关资源
最近更新 更多