strtod() で double を正しく解析するには、スレッドのロケールを変更する必要があります。これには setlocale() を使用しています (C++)。スレッドセーフですか?
更新: 別の問題。main() 関数で setlocale() を呼び出すと、他のルーチンには影響しません。どうして???コードが多いので、チャンクを書くのが面倒です。
C++11 では、標準スレッドが言語の一部としてサポートされるようになりました。標準は、setlocale() 呼び出しが、setlocale() への他の呼び出しまたは strtod() を含む現在の C ロケールの影響を受ける関数への呼び出しとのデータ競合を導入することを明示的に呼び出します。locale::global() 関数は、setlocale() を呼び出したかのように動作すると見なされるため、データ競合が発生する可能性もあります (後述)。
glibc を使用する Linux では、MT-unsafe (const:locale env)で、スレッドが setlocale() を非 NULL 引数で同時に呼び出し、グローバル ロケールを使用する可能性のある他の関数を呼び出す (データ競合と C11 での未定義の動作) . 代わりに、MT セーフであり、呼び出しスレッドのロケールのみを変更するuselocale()を使用することをお勧めします。C++ コードで libstdc++ を使用する Linux では、locale::global (プロセス全体の変更) を避け、スレッドが使用するロケールを作成する必要があります (locale::global は、C ランタイムと同じ理由で MT-unsafe です)。strtod (C API) を使用するという目標を考えると、uselocale() を使用する必要があります。
glibc を使用する Linux では、setlocale() 関数自体は、2 つの厳密な基準を満たさない限り MT-unsafe であり、POSIX で要求されるように、プロセス全体のロケールを変更します。新しい Linux man ページ ( Red Hat と富士通の取り組みの一部で、すべての API の MT セーフ表記を指定しています) は、 setlocale()をマークします。「MT-Unsafe const:locale env」として、setlocale が MT-safe IFF であることを意味し、(変更せず、NULL を渡して照会するだけで) ロケールを一定に保ち、ロケールと環境を一定に保つ場合 (引数が "" の場合は、ロケールの変更を避けてください)。glibc を使用する Linux では、呼び出しスレッドのロケールのみを変更する場合は、uselocale() を使用する必要があります。これは、MT セーフであり、環境にまったく依存せず、strtod がスレッドのロケールを使用するためです。同様に、POSIX を実装するすべてのシステムは、スレッド コンテキスト (MT セーフ) で使用するために uselocale() を提供する必要があります。
OS X は uselocale() を実装しているので、それを使用できます。
Windows では、_configthreadlocale を使用して setlocale() がプロセスまたはスレッド全体で動作するかどうかを変更します (必要な uselocale に変換します)。ただし、C++ コードの場合は、locale クラスのインスタンスを使用し、 locale::global を避ける必要があります。
setlocale()の呼び出しはスレッドセーフである場合とそうでない場合がありますが、ロケール設定自体はプロセスごとであり、スレッドごとではありません。つまり、setlocale()がスレッドセーフであるか、ミューテックスを使用して自分自身を保護している場合でも、変更によってすべてのスレッドの現在のロケールが更新されます。
ただし、スレッドごとの代替手段があります:uselocale()。
#include <xlocale.h>
locale_t loc = newlocale(LC_ALL_MASK, "nl_NL", NULL);
uselocale(loc);
freelocale(loc)
// Do your thing
ロケールは内部で参照カウントを使用します。そのため、newlocale()でアクティブ化した後、ロケールを解放しても安全です。
使用している実装のドキュメントを参照する必要があります。C++ は現在、スレッドについて何も指定していないため、実装に帰着します (まだ教えてくれていません)。
たとえば、setlocale の Linux マンページには次のスニペットがあります。
この文字列は、静的ストレージに割り当てることができます。
それがスレッドセーフでないことを絶対に示しているわけではありませんが、私は非常に用心しています。NULLで呼び出す (つまり、クエリを実行する) ことはスレッド セーフである可能性がありますが、それを変更するスレッドがあるとすぐに、すべての賭けはオフになります。
おそらく最も安全な方法は (スレッドセーフではないと仮定して) へのすべての呼び出しをsetlocale
ミューテックスで保護し、次の行に沿って数値をフォーマットする特別な関数を用意することです。
claim mutex
curr = setlocale to specific value
format number to string
setlocale to curr
release mutex
return string
C++98 の場合、コンパイラと、選択したランタイム ライブラリと、スレッド セーフとは正確には何を意味するかによって異なります。
たとえば、MSVC とマルチスレッド ランタイムでは、setlocale
それ自体が安全である必要があります。しかし、スレッドごとのロケールは得られないと思います。setlocale
スレッドごとのロケールではなく、グローバル ロケールに使用します。
C++98 は、スレッド化 (さらに言えば、動的ライブラリー) に対応していません。
C 言語はスレッド ローカルをサポートします。http://msdn.microsoft.com/en-us/library/ms235302.aspxをお読みください。主なメソッドは次のとおりです: _configthreadlocale(_ENABLE_PER_THREAD_LOCALE)