Является ли setlocale поточно-ориентированной функцией? - PullRequest
9 голосов
/ 30 октября 2010

Мне нужно изменить локаль в потоке, чтобы правильно анализировать double с помощью strtod (), для этого я использую setlocale () (C ++). Это потокобезопасно?

Обновление: еще одна проблема. Когда я вызываю setlocale () в моей функции main (), это не затрагивает другие подпрограммы глубже. Зачем??? Там много кода, поэтому написать блок проблематично.

Ответы [ 6 ]

7 голосов
/ 23 февраля 2016

В C ++ 11 стандартные потоки теперь являются поддерживаемой частью языка.Стандарт явно указывает, что вызовы setlocale () вводят гонки данных с другими вызовами setlocale () или вызовы функций, на которые влияет текущая локаль C, включая strtod ().Считается, что функция locale :: global () ведет себя так, как если бы она вызывала setlocale (), поэтому она также может вводить гонку данных (см. Ниже).

В Linux с glibc это MT-unsafe (const: locale env) чтобы потоки вызывали setlocale () одновременно с аргументом, отличным от NULL, и вызывали любую другую функцию, которая могла бы использовать глобальный языковой стандарт (гонка данных и, следовательно, неопределенное поведение в C11).Вместо этого предлагается использовать uselocale () , которая безопасна для MT и изменяет только локаль вызывающего потока.В Linux с libstdc ++ в коде C ++ вы должны избегать locale :: global (изменение процесса в целом) и создавать локаль для использования потока (locale :: global является MT-unsafe по тем же причинам, что и среда выполнения C).Учитывая вашу цель использовать strtod (C API), вы должны использовать uselocale ().

В Linux, использующем glibc, функция setlocale () сама по себе является MT-небезопасной, если вы не соответствуете 2 строгим критериям и в соответствии с требованиями POSIXменяет локаль для всего процесса.Новые справочные страницы Linux (часть Red Hat и Fujitsu работают над указанием нотаций MT-безопасности для всех API ) помечают setlocale () как "MT-Unsafe const: locale env", что означает, что setlocale является MT-безопасным IFF, вы сохраняете константу локали (не изменяя ее, просто запрашивая ее, передавая NULL), и если вы сохраняете константу локали и среды (чтобы избежать изменений в локали, если аргумент равен "«).В Linux, использующем glibc, вы должны использовать uselocale (), если вы хотите изменить только локаль вызывающего потока, поскольку это MT-безопасно и никак не зависит от вашей среды, а strtod будет использовать локаль потока.Точно так же все системы, которые реализуют POSIX, должны предоставлять uselocale () для использования в контексте потока (MT-safe).

OS X реализует uselocale (), так что вы можете использовать это.

При использовании Windows_configthreadlocale для изменения, если setlocale () работает со всем процессом или потоками (превращает его в uselocale, что вам нужно), но для кода C ++ вам снова нужно использовать экземпляр класса locale и избегать locale :: global .

7 голосов
/ 10 июня 2011

Вызов setlocale () может быть или может не быть потокобезопасным, но сама настройка локали для каждого процесса, а не для потока.Это означает, что даже если вы setlocale () поточно-ориентированы или используете мьютекс, чтобы защитить себя, изменение все равно обновит текущую локаль для всех ваших потоков.

Хотя есть альтернатива для каждого потока:uselocale ().

#include <xlocale.h>

locale_t loc = newlocale(LC_ALL_MASK, "nl_NL", NULL);
uselocale(loc);
freelocale(loc)
// Do your thing

В локали внутренне используется подсчет ссылок, поэтому его можно безопасно освободить после активации с помощью newlocale ().

3 голосов
/ 30 октября 2010

Вам необходимо обратиться к документации для любой реализации, которую вы используете. C ++ в настоящее время ничего не указывает о потоках, поэтому речь идет о реализации (о которой вы еще не сказали).

Например, у моей man-страницы Linux для setlocale есть фрагмент:

Эта строка может быть размещена в статическом хранилище.

, что не означает, что это небезопасно, но я бы очень осторожен. вероятно , что вызов его с помощью NULL (т. Е. Запросов) будет поточно-ориентированным, но как только у вас есть поток, модифицирующий его, все ставки отключаются.

Вероятно, самый безопасный способ сделать (при условии, что он не поддерживает потоки) - это защитить все вызовы на setlocale мьютексом и иметь специальную функцию для форматирования ваших чисел вдоль линий из:

claim mutex
curr = setlocale to specific value
format number to string
setlocale to curr
release mutex
return string
2 голосов
/ 30 октября 2010

Для C ++ 98 это зависит от компилятора и от того, какую библиотеку времени выполнения вы выбираете и от того, что именно вы подразумеваете под потокобезопасностью.

например. с MSVC и многопоточным временем выполнения вы должны быть в безопасности в том смысле, как и setlocale. Но я не думаю, что вы получите локаль для каждого потока. Используйте setlocale для глобальной локали, а не для локали для каждого потока.

C ++ 98 не рассматривает многопоточность (или, в этом отношении, динамические библиотеки).

1 голос
/ 31 декабря 2013

C язык поддерживает локальный поток. Пожалуйста, прочитайте http://msdn.microsoft.com/en-us/library/ms235302.aspx. Основные методы: _configthreadlocale (_ENABLE_PER_THREAD_LOCALE)

0 голосов
/ 20 марта 2017

Для решения второй части исходного вопроса:

Функция setlocale находится в библиотеке C (как определено в среде C ++ стандартным заголовком <clocale>), и ее использование повлияет только наC библиотека подпрограмм.Вы упоминаете C ++ в первой части вашего вопроса, поэтому мне интересно, ожидаете ли вы, что подпрограммы C ++ примут к сведению изменения локали, сделанные с помощью setlocale.Мой опыт говорит, что они не будут.

Надлежащие методы работы с информацией о локали в C ++ определяются библиотекой, указанной в стандартном заголовке C ++ <locale>.Эта библиотека обеспечивает управление информацией о локали способом, совместимым с операциями ввода-вывода C ++.Например, вы можете создать std::locale объект с определенными характеристиками, а затем наполнить std::filebuf этим объектом, чтобы операции ввода-вывода соответствовали этим характеристикам.

Если вы работаете в смешанном C / C ++окружение, используйте std::locale::global() - с правильным параметром, он также устанавливает глобальную локаль C, как если бы функция библиотеки C setlocale была вызвана с LC_ALL.Это обеспечит синхронизацию функций библиотеки C и C ++.

...