Подтвердить что ты не робот

Является std::string безопасным с gcc 4.3?

Я разрабатываю многопоточную программу, запущенную на Linux (скомпилированную с g++ 4.3), и если вы немного поискаете, вы найдете много страшных историй о std::string, которые не являются потокобезопасными с GCC. Это, предположительно, связано с тем, что внутри он использует copy-on-write, который наносит ущерб инструментам вроде Helgrind.

Я сделал небольшую программу, которая копирует одну строку в другую строку, и если вы проверите обе строки, они оба будут иметь один и тот же внутренний указатель _M_p. Когда одна строка изменена, указатель изменяется, поэтому материал "копировать-на-запись" работает нормально.

Я беспокоюсь о том, что происходит, если я разделяю строку между двумя потоками (например, передавая ее как объект в потоковом потоке данных между двумя потоками). Я уже пробовал компиляцию с параметром "-pthread", но это, похоже, не имеет большого значения. Поэтому мой вопрос:

  • Есть ли способ заставить std::string быть потокобезопасным? Я бы не возражал, если для этого было отключено поведение "копирование по-записи".
  • Как другие люди решили это? Или я параноик?

Я не могу найти окончательного ответа, поэтому надеюсь, что вы, ребята, можете мне помочь..

Edit:

Ничего себе, за это очень много ответов. Спасибо! Я обязательно буду использовать решение Jack, когда я хочу отключить COW. Но теперь главный вопрос: действительно ли мне нужно отключить COW? Или это "бухгалтерия", сделанная для поточной безопасности COW? В настоящее время я просматриваю источники libstdС++, но это займет довольно много времени, чтобы выяснить...

Изменить 2

OK просмотрел исходный код libstdС++, и я нашел что-то вроде этого в libstd ++ - v3/include/bits/basic_string.h:

  _CharT*
   _M_refcopy() throw()
   {
#ifndef _GLIBCXX_FULLY_DYNAMIC_STRING
     if (__builtin_expect(this != &_S_empty_rep(), false))
#endif
            __gnu_cxx::__atomic_add_dispatch(&this->_M_refcount, 1);
     return _M_refdata();
   }  // XXX MT

Итак, есть что-то там об атомных изменениях на счетчике...

Заключение

Я отмечаю комментарий sellibitze как ответ здесь, потому что, думаю, мы пришли к выводу, что эта область до сих пор не решена. Чтобы обойти поведение COW, я бы предложил ответить Джеку Ллойду. Спасибо всем за интересное обсуждение!

4b9b3361

Ответ 1

Нити еще не являются частью стандарта. Но я не думаю, что любой поставщик может уйти, не делая std::string потокобезопасным, в настоящее время. Примечание. Существуют разные определения "поточно-безопасные", и мои могут отличаться от ваших. Конечно, нет смысла защищать контейнер, например std::vector, для одновременного доступа по умолчанию, даже если он вам не нужен. Это противоречило бы духу С++, "не платите за то, что вы не используете". Пользователь должен всегда отвечать за синхронизацию, если он хочет делиться объектами между различными потоками. Здесь проблема заключается в том, использует ли библиотечный компонент и разделяет некоторые скрытые структуры данных, которые могут привести к расам данных, даже если "функции применяются к различным объектам" с точки зрения пользователя.

Проект С++ 0x (N2960) содержит раздел "Уклонение от гонки данных", в котором в основном говорится, что компоненты библиотеки могут обращаться к общим данным, скрытым от пользователя, тогда и только тогда, когда он активно избегает возможных гонок данных. Похоже, что реализация std:: basic_string для копирования на запись должна быть безопасной w.r.t. многопоточность в качестве другой реализации, где внутренние данные никогда не используются для разных экземпляров строк.

Я не уверен, что libstdС++ позаботится об этом уже на 100%. Я думаю, что так и есть. Разумеется, посмотрите документацию

Ответ 2

Если вы не против отключения копирования на запись, это может быть лучший способ действий. std::string COW работает только в том случае, если он знает, что он копирует другой std::string, поэтому вы можете заставить его всегда выделять новый блок памяти и делать фактическую копию. Например, этот код:

#include <string>
#include <cstdio>

int main()
   {
   std::string orig = "I'm the original!";
   std::string copy_cow = orig;
   std::string copy_mem = orig.c_str();
   std::printf("%p %p %p\n", orig.data(),
                             copy_cow.data(),
                             copy_mem.data());
   }

покажет, что вторая копия (с использованием c_str) предотвращает COW. (Потому что std::string видит только голый const char * и не знает, откуда он пришел или что может быть его время жизни, поэтому он должен создать новую частную копию).

Ответ 3

Этот раздел из внутренних компонентов libstdС++:

Функциональность строки библиотеки С++ требует нескольких атомных операций для обеспечения безопасности потока. Если вы не предпринимать какие-либо специальные действия, библиотека будут использовать версии-заглушки этих функции, которые не являются потокобезопасными. Они будут работать нормально, если только ваши приложения многопоточны.

Счет ссылок должен работать в многопоточной среде. (если ваша система не предоставляет необходимые атомы)

Ответ 4

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

Ответ 6

В соответствии с эта проблема с ошибкой, реализация std::basic_string copy-on-write все еще не полностью поточно-безопасна. <ext/vstring.h> - это реализация без COW и, похоже, намного лучше в контексте только для чтения.