Разумно ли заменить boost :: thread и boost :: mutex на c ++ 11 эквивалентов? - PullRequest
148 голосов
/ 30 августа 2011

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

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

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

Ответы [ 7 ]

186 голосов
/ 30 августа 2011

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

  • Boost поддерживает отмену потоков, потоки C ++ 11 не
  • C ++11 поддерживает std::async, но Boost не
  • Boost имеет boost::shared_mutex для блокировки нескольких считывателей / одного записывающего устройства.Аналогичный std::shared_timed_mutex доступен только с C ++ 14 ( N3891 ), а std::shared_mutex доступен только с C ++ 17 ( N4508 ).
  • Тайм-ауты C ++ 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() для объекта потока, который уничтожается / присваивается.Для объекта C ++ 11 std::thread это приведет к вызову std::terminate() и отмене приложения.

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

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

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

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

23 голосов
/ 30 августа 2011

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

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

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

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

6 голосов
/ 02 марта 2016

Корпоративный кейс

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

Базовый / Технический случай запуска

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

Мой опыт

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

6 голосов
/ 15 марта 2014

Существует одна причина не переходить на std::thread.

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

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

3 голосов
/ 06 января 2015

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

1 голос
/ 10 мая 2019

Относительно std :: shared_mutex, добавленного в C ++ 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.

0 голосов
/ 28 мая 2014

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

Повышение имеет также больше возможностей. Например, заголовок в версии std не предоставляет сериализатор потоку (то есть cout << duration). Boost имеет много библиотек, которые используют собственные эквиваленты и т. Д., Но не взаимодействуют с версиями std. </p>

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

...