Является ли разумным заменить boost:: thread и boost:: mutex на С++ 11 эквивалентов?

Мотивация: причина, по которой я рассматриваю это, заключается в том, что мой гениальный менеджер проекта думает, что повышение - это еще одна зависимость, и что это ужасно, потому что "вы зависите от этого" (я попытался объяснить качество повышения, а затем сдался после некоторых time:(). Меньшая причина, по которой я хотел бы это сделать, это то, что я хотел бы изучить возможности С++ 11, потому что люди начнут писать код в нем. Итак:

  • Существует ли отображение 1:1 между #include<thread> #include<mutex> и повышающие эквиваленты?
  • Вы считаете хорошей идеей заменить boost с помощью С++ 11
    вещи. Мое использование примитивно, но есть примеры, когда std doesnt предложите, что толчок? Или (богохульство) наоборот?

P.S. Я использую GCC, поэтому есть заголовки.

Ответ 1

Существует несколько различий между Boost.Thread и стандартной библиотекой потоков С++ 11:

  • Boost поддерживает отмену потока, потоки С++ 11 не
  • С++ 11 поддерживает std::async, но Boost не
  • Boost имеет boost::shared_mutex для блокировки с несколькими считывателями/одиночными авторами. Аналогичный std::shared_timed_mutex доступен только с С++ 14 (N3891), а std::shared_mutex доступен только с С++ 17 (N4508).
  • Тайм-ауты С++ 11 отличаются от тайм-аутов Boost (хотя это скоро должно измениться теперь Boost.Chrono было принято).
  • Некоторые имена различаются (например, boost::unique_future vs std::future)
  • Семантика аргумента std::thread отличается от boost::thread - Boost использует boost::bind, для чего требуются скопируемые аргументы. std::thread позволяет передавать только типы перемещения, такие как std::unique_ptr, как аргументы. Из-за использования boost::bind семантика заполнителей, таких как _1 во вложенных выражениях связей, также может быть разной.
  • Если вы явно не вызываете join() или detach(), тогда оператор деструктора и назначения boost::thread вызовет detach() на объект потока, который будет уничтожен/назначен. С объектом С++ 11 std::thread это приведет к вызову std::terminate() и прервет работу приложения.

Чтобы прояснить суть параметров только для перемещения, допустимо С++ 11 и переносит право собственности на int из временного std::unique_ptr на параметр f1 при запуске нового потока, Однако, если вы используете boost::thread, тогда он не будет работать, поскольку он использует boost::bind внутри, а std::unique_ptr не может быть скопирован. Также существует ошибка в библиотеке потоков С++ 11, предоставляемой с помощью GCC, которая мешает этой работе, поскольку она также использует std::bind в реализации.

void f1(std::unique_ptr<int>);
std::thread t1(f1,std::unique_ptr<int>(new int(42)));

Если вы используете Boost, вы можете, вероятно, переключиться на потоки С++ 11 относительно безболезненно, если ваш компилятор поддерживает его (например, последние версии GCC на linux имеют в основном полную реализацию библиотеки потоков С++ 11, доступной в -std=c++0x).

Если ваш компилятор не поддерживает потоки С++ 11, вы можете получить стороннюю реализацию, такую ​​как Just:: Thread, но это все еще является зависимостью.

Ответ 2

std::thread в значительной степени моделируется после boost::thread, несколько различий:

  • форматировать не скопируемые, одно-ручные-карты-к-одному-os-thread, семантика сохраняется. Но этот поток является подвижным, чтобы позволить возвращать поток из функций factory и помещать в контейнеры.
  • Это предложение добавляет отмену boost::thread, что является значительным осложнением. Это изменение оказывает большое влияние не только на поток, но и на остальную библиотеку потоков С++. Считается, что это большое изменение оправдано из-за выгоды.
    • Теперь деструктор потока должен отменить отмену перед отсоединением, чтобы избежать случайного утечки дочерних потоков при отмене родительских потоков.
    • Теперь требуется явный элемент отсоединения, чтобы включить отключение без отмены.
  • Понятия дескриптора потока и идентичности потоков были разделены на два класса (они являются одним и тем же классом в boost::thread). Это упрощает управление и хранение идентификаторов потоков.
  • Добавлена ​​возможность создания идентификатора потока, который, как гарантируется, сравнивается с любым другим соединяемым потоком (boost::thread не имеет этого). Это удобно для кода, который хочет знать, выполняется ли он тем же потоком, что и предыдущий вызов (рекурсивные мьютексы являются конкретным примером).
  • Существует "задняя дверь", чтобы получить дескриптор собственного потока, чтобы клиенты могли манипулировать потоками с использованием базовой ОС, если это необходимо.

Это с 2007 года, поэтому некоторые пункты больше не действительны: boost::thread теперь имеет функцию native_handle, и, как отмечают комментаторы, std::thread больше не отменяет.

Я не мог найти существенных различий между boost::mutex и std::mutex.

Ответ 3

Есть одна причина не переходить на std::thread.

Если вы используете статическое связывание, std::thread становится непригодным для использования из-за следующих ошибок/возможностей gcc:

А именно, если вы вызовете std::thread::detach или std::thread::join это приведет либо к исключению, либо к сбою, тогда как boost::thread работает нормально в этих случаях.

Ответ 4

Корпоративный случай

Если вы пишете программное обеспечение для предприятия, которое должно работать на умеренных или больших операционных системах и, следовательно, собирать с различными компиляторами и версиями компиляторов (особенно относительно старых) для этих операционных систем, я советую вам избегать С++ 11 в целом на данный момент. Это означает, что вы не можете использовать std::thread, и я бы рекомендовал использовать boost::thread.

Базовый /Tech Startup Case

Если вы пишете для одной или двух операционных систем, вы наверняка знаете, что вам когда-либо понадобится строить только с помощью современного компилятора, который в основном поддерживает С++ 11 (например, VS2015, GCC 5.3, Xcode 7), и вы этого еще не сделали в зависимости от библиотеки наддува, std::thread может быть хорошим вариантом.

Мой опыт

Я лично неравнодушен к закаленным, интенсивно используемым, высоко совместимым, высокосогласованным библиотекам, таким как boost по сравнению с очень современной альтернативой. Это особенно верно для сложных предметов программирования, таких как многопоточность. Кроме того, я уже давно добился большого успеха с boost::thread (и boost в целом) в широком спектре сред, компиляторов, потоковых моделей и т.д. Когда это мой выбор, я выбираю boost.

Ответ 5

С Visual Studio 2013 std::mutex, похоже, ведет себя иначе, чем boost::mutex, что вызвало у меня некоторые проблемы (см. этот вопрос).

Ответ 6

Что касается std :: shared_mutex, добавленного в С++ 17

Другие ответы здесь дают очень хороший обзор различий в целом. Однако есть несколько проблем с std::shared_mutex которые буст решает.

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

  2. Честность. Если у вас есть постоянная активность чтения с помощью std::shared_mutex, ваши авторы будут заблокированы на неопределенный срок. Это потому, что если придет другой читатель, им всегда будет отдан приоритет. С boost:shared_mutex все потоки в конечном итоге получат приоритет. (1) Ни читатели, ни писатели не будут голодать.

Суть этого в том, что если у вас система с очень высокой пропускной способностью, без простоев и с высокой конкуренцией, std::shared_mutex никогда не будет работать для вас без ручной сборки системы приоритетов поверх нее. boost::shared_mutex будет работать из коробки, хотя в некоторых случаях вам, возможно, придется поработать с ним. Я бы сказал, что поведение std::shared_mutex - это скрытая ошибка, ожидающая своего появления в большинстве кодов, которые его используют.

(1)Фактический алгоритм, который он использует, основан на планировщике потоков ОС.По моему опыту, когда чтение насыщено, паузы (при получении блокировки записи) в Windows длиннее, чем в OSX/Linux.

Ответ 7

Я попытался использовать shared_ptr из std вместо boost, и я действительно нашел ошибку в gcc-реализации этого класса. Мое приложение рушилось из-за двойного вызова деструктора (этот класс должен быть потокобезопасным и не должен генерировать такие проблемы). После перехода на boost:: shared_ptr все проблемы исчезли. Текущие реализации С++ 11 все еще не зрелые.

У Boost есть еще больше возможностей. Например, заголовок в версии std не предоставляет сериализатор потоку (т.е. Cout < продолжительность). У Boost есть много библиотек, которые используют свои собственные и т.д. Эквиваленты, но не взаимодействуют со стандартными версиями.

Подводя итог - если у вас уже есть приложение, написанное с использованием boost, безопаснее хранить ваш код, как он есть, вместо того чтобы приложить некоторые усилия при переходе к стандарту С++ 11.