LINUX.ORG.RU

POSIX threads vs std / boost

 ,


0

4

Из темы Отладка ошибки многопоточности

Назовите мне хоть одну реальную причину, по которой имеет смысл использовать в проекте на C++ POSIX threads вместо std::thread / boost::thread.

Пока я вижу только две:

  • Запрет использования C++11 / C++14 / C++17 (старый компилятор, требование компании etc)
  • Старый проект, в котором уже написаны свои обёртки над POSIX thread'ами

Кто ещё в здравом уме будет скатываться до API системы, когда в языке есть более высокоуровневое средство для решения той же задачи? Это всё равно, что советовать для проектов под Windows использовать CreateThread / _beginthread / _beginthreadex вместо всё тех же std / boost.

Баги? На какие лично вы натыкались?

Производительность? Обычно проблемы производительности, связанные с синхронизацией потоков, вызваны хреновой архитектурой, а вовсе не тем, что используется std::mutex вместо pthread_mutex_t.



Последнее исправление: b0r3d0m (всего исправлений: 1)

std не перекрывает все возможности/атрибуты pthread. Впрочем, никто не запрещает прикрыть препроцессором такие места (а их может и не быть вовсе), и по по умолчанию использовать std.

anonymous
()
Ответ на: комментарий от anonymous

Ну если надо, можно создать свою расширенную оберточку над std/boost::thread унаследованную от/агрерирующий в себя std::boost::thread. Это в любом случае лучше, чем городить си ужас.

Dudraug ★★★★★
()
Последнее исправление: Dudraug (всего исправлений: 2)

Производительность? Обычно проблемы производительности, связанные с синхронизацией потоков, вызваны хреновой архитектурой, а вовсе не тем, что используется std::mutex вместо pthread_mutex_t.

В соседнем треде была высказана идея, что если ты не юзаешь системные оптимизации через ifdefы или даже ассемблер, то это детские проекты и им с++ не нужен вообще=)

Dudraug ★★★★★
()
Ответ на: комментарий от Dudraug

Призываю мамкиного максималиста в тред.

b0r3d0m
() автор топика
Ответ на: комментарий от Dudraug

Как можно сделать такую оберточку, чтобы перед стартом нити иметь возможность указать размер стека для новой нити и, скажем, прибить нить к конкретному ядру (через pthread_attr_setaffinity_np)?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

В чём проблема использовать std::thread и при действительной необходимости использования отсутствующего в нём функционала брать std::thread::native_handle?

b0r3d0m
() автор топика

Старый проект, в котором уже написаны свои обёртки над POSIX thread'ами

Но это как раз причина _не_ использовать pthreads.

tailgunner ★★★★★
()
Ответ на: комментарий от eao197

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

Dudraug ★★★★★
()
Ответ на: комментарий от tailgunner

Ну, да. Смотря с какой стороны посмотреть. В таком случае надо использовать эту самую обёртку, но внутри как раз и будут спрятаны pthreads.

b0r3d0m
() автор топика
Ответ на: комментарий от eao197

Как можно сделать такую оберточку, чтобы перед стартом нити иметь возможность указать размер стека для новой нити и, скажем, прибить нить к конкретному ядру (через pthread_attr_setaffinity_np)?

Для второго есть native_handle.

tailgunner ★★★★★
()
Ответ на: комментарий от b0r3d0m

Ну так покажите как установить такие свойства нити, как stack size и affinity, до запуска нити через std::thread.

eao197 ★★★★★
()
Ответ на: комментарий от Dudraug

Есть у меня подозрение, что Iron_Bug по роду своей деятельности занимается низкоуровневым системным или околосистемным программированием. Посему есть и понимание, и необходимость.

Т.е. поинт в том, что пока нет надобности на всю катушку использовать возможности нижележащей ОС, то std::thread вполне хватит. А если такая надобность возникает, то std::thread приходится откладывать в сторону.

eao197 ★★★★★
()
Ответ на: комментарий от tailgunner

native_handle есть не для второго. А для управления уже созданной нитью. У меня речь шла о назначении атрибутов нити до ее создания.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

У меня речь шла о назначении атрибутов нити до ее создания.

Шашечки или ехать. Аффинити можно поставить и уже созданной нити.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Шашечки или ехать. Аффинити можно поставить и уже созданной нити.

Так это как раз ты предлагаешь шашечки. Сначала запустить нить хрен знает где, затем поменять ей аффинити. Там, где за этим приходится следить, такой сценарий ну очень сильно неправильный.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Сначала запустить нить хрен знает где, затем поменять ей аффинити.

Именно так.

Там, где за этим приходится следить, такой сценарий ну очень сильно неправильный.

Это не подходит там, где нити короткоживущие, нет возможности сделать нормальный протокол инициализации, и даже нельзя вызвать set_affinity в нити-родителе. Т.е. много неестественных ограничений.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от b0r3d0m

(для std), хотя в boost всё равно менее эффективно реализованно чем в pthread

для std можно вагон вариантов придумать, начиная от аффинити и заканчивая просранным shared_lock вполть до 14-ого стандарта.

на вскидку что не умеет ни тот ни тот - имена потоков

pon4ik ★★★★★
()
Ответ на: комментарий от pon4ik

Вопрос в том, насколько это всё надо и что именно из того, что стоит сделать, невозможно сделать через native_handle.

просранным shared_lock

Как печально, что люди до сих пор пользуются непосредственно локами.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

А почему печально?

Во-первых если спичек у тебя вагоны то и на них можно мильёны сэкономить. Во-вторых не такая уж это и низкоуровневая абстракция, часто господа гораздо глубже влезают, что бы доставшимися квантами распорядиться как надо.

pon4ik ★★★★★
()
Ответ на: комментарий от tailgunner

Как печально, что люди до сих пор пользуются непосредственно локами.

А чем же нужно пользоваться?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

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

Iron_Bug ★★★★★
()
Ответ на: комментарий от pon4ik

Во-первых если спичек у тебя вагоны то и на них можно мильёны сэкономить

Если у тебя очень много вагонов спичек... то всё равно нельзя.

часто господа гораздо глубже влезают

Господам просто интересно.

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

Потерять полкоробки зажигалок гораздо проще чем вагон спичек, если продолжать метафору.

pon4ik ★★★★★
()
Ответ на: комментарий от tailgunner

что люди до сих пор пользуются непосредственно локами.

Lock-free — сладенький миф. lock-free = те же локи, но скрытые обскурно где-то в кишках. В целом это удобно, но не всегда. Даже если у тебя все данные иммутабильные, все равно будет ввод-вывод, на который придется навесить лок.

anonymous
()
Ответ на: комментарий от eao197

Как печально, что люди до сих пор пользуются непосредственно локами.

А чем же нужно пользоваться?

Абстракциями более высокого уровня, очевидно же. Примитивный CSP пишется за пару дней и реально облегчает жизнь. Думаю, в новых Си++ есть и стандартные средства более высокого уровня (future и прочее).

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от anonymous

что люди до сих пор пользуются непосредственно локами.

Lock-free — сладенький миф

Казалось бы, причем тут.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Абстракциями более высого уровня, очевидно же.

Имя, сестра, имя! :)

Примитивный CSP пишется за пару дней и реально облегчает жизнь.

Ну а у него внутрях что будет? Неужели не mutex/shared_mutex?

Думаю, в новых Си++ есть и стандартные средства более высокого уровня (future и прочее).

Тебе не кажется, что mutex/condition, future и CSP — это все для несколько разных направлений предназначено?

eao197 ★★★★★
()
Ответ на: комментарий от tailgunner

«Примитивный CSP» — это не для джедаев оптимизации :)

«стандартные средства более высокого уровня (future и прочее)» — ага, не успели (феерически криво) добавить, а уже депрекейтить собираются

anonymous
()
Ответ на: комментарий от eao197

Примитивный CSP пишется за пару дней и реально облегчает жизнь.

Ну а у него внутрях что будет? Неужели не mutex/shared_mutex?

Естественно. Но они будут строго внутри, а снаружи - нормальный send/recv.

Тебе не кажется, что mutex/condition, future и CSP — это все для несколько разных направлений предназначено?

Ха, да я точно знаю, что mutexes/condvars предназначены для создания своих, высокоуровневых и foolproof примитивов синхронизации. Но, к моей печали, так мало кто делает - народ хреначит сырые мютексы all over the map.

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

«Примитивный CSP» — это не для джедаев оптимизации :)

Лучше бы эти джедаи сидели в свое galaxy far, far away.

tailgunner ★★★★★
()
Ответ на: комментарий от pon4ik

просранным shared_lock

Как написали выше, блокировок лучше избегать. Без них не обойтись в общем случае, но они должны быть максимально локализованы, прикрывать примитивнейший и быстрый код, и в идеале спрятаны за абстракциями. Если же строить на их основе всю логику - будут и deadlock'и и неэффективное исполнение. И данный shared_lock, как по мне, поощряет создавать неправильную архитектуру (хоть и не заставляет). Но это ИМХО, конечно.

anonymous
()
Ответ на: комментарий от anonymous

«сладенький миф» работает в крупных сетевых проектах на всю катушку. но для этого действительно нужна серьёзная потребность в таких вещах, а не просто с потолка взять и прилепить lock-free к какому-то наколеночному проектику размером в несколько тыщ строк кода. он там будет как собаке пятая нога. более того, я сейчас активно исследую тему lock-free работы в ядре и создание отдельных, разделённых по процессорам, очередей обработки TCP-стека. но это точно уже не относится к среднестатистическому программированию. хотя юзерспейс, в принципе, можно и на плюсах наваять. просто профита не получится: там возня врукопашную с байтами и «плюсы» плюсов там будут невостребованы.

Iron_Bug ★★★★★
()
Ответ на: комментарий от anonymous

Я конечно не претендую на вселенскую истинну, но кроме как более низкоуровневыми средствами, я слабо представляю эффективную релизацию multiple reader single writer без shared_lock. Вот дозахват - это зло, придуманное для 1.5 случаев.

pon4ik ★★★★★
()
Ответ на: комментарий от tailgunner

Ха, да я точно знаю, что mutexes/condvars предназначены для создания своих, высокоуровневых и foolproof примитивов синхронизации. Но, к моей печали, так мало кто делает - народ хреначит сырые мютексы all over the map.

Не обязательно. Примитивы синхронизации незаменимы там, где без работы над общими разделяемыми данными не обойтись. Ну или же придется городить огород из lock-free структур данных. Или же делать какой-то вариант RCU.

Далеко не всегда можно уйти к асинхронному взаимодействию и работе в режиме share nothing.

Другое дело, что многие разработчики вообще дальше mutex-ов и condition-ов в изучении многопоточности не идут.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

просто плюсы выродятся в обычную сишечку. потому что все навороты плюсов отъедают производительность, ради которой вся возня. плюсы можно использовать, как Си. но есть ли тогда смысл писать именно на плюсах? я лично если не вижу преимуществ именно плюсов, то пишу на чистой сишечке, без выпендрёжа. и по большей части в околосистемном программировании нигде и не нужны ни ООП, ни исключения, ни кроссплатформенность.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от eao197

Примитивы синхронизации незаменимы там, где без работы над общими разделяемыми данными не обойтись

Что значит «незаменимы»? Доказано, что они заменимы во всех случаях.

Далеко не всегда можно уйти к асинхронному взаимодействию и работе в режиме share nothing.

Естественно, всегда будут исключения. Но дефолтным режимом должно быть именно использование приличных абстракций. А низкоуровневые не нужны почти никогда.

Другое дело, что многие разработчики вообще дальше mutex-ов и condition-ов в изучении многопоточности не идут.

О результатах этого я и печалюсь.

tailgunner ★★★★★
()
Ответ на: комментарий от Iron_Bug

по большей части в околосистемном программировании нигде и не нужны ни ООП, ни исключения, ни кроссплатформенность

Если что, в Си++ есть еще и параметризуемые типы данных. Они нужны даже в трижды насквозь системном программировании.

tailgunner ★★★★★
()
Ответ на: комментарий от Iron_Bug

потому что все навороты плюсов отъедают производительность

Так уж и все? Например, тот же enum class из C++11? Или шаблоны? Или лямбы, которые можно использовать в качестве локальных функций?

Например, много ли накладных расходов будет на вот такой код:

using file_ptr=std::unique_ptr<std::FILE, void(*)(std::FILE*)>;
...
file_ptr file(std::fopen(...), std::fclose);
if(!file) return -1;
...

eao197 ★★★★★
()
Ответ на: комментарий от utf8nowhere

вооот! это и есть причина использовать pthread, например. что касается буста, то чаще всего из тестов выходило, что он гораздо тормознее простых системных вызовов. оно и понятно: кроссплатформенность требует жертв. поэтому иногда я в качестве основы использовала буст (например, для кроссплатформы), но дополненный кастомизациями под систему в тех местах, где это было критично. у меня раньше были даже свои патчи для буста, для повышения скорости его работы :) правда, я уже давно перешла в работе на Линюкс и больше не парю себе мозг. буст - забавная штука в плане того, чтобы посмотреть, а что там в стандартах зреет. но применять его нужно с осторожностью. впрочем, он всяко шустрее Qt. но если серьёзно заморачиваться кроссплатформой и скоростью, то только ACE. он имеет жуткий интерфейс, неудобную документацию, но по скорости он уделывает на корню и boost, и тем более Qt.

Iron_Bug ★★★★★
()
Ответ на: комментарий от tailgunner

Что значит «незаменимы»? Доказано, что они заменимы во всех случаях.

Правда?

Ну вот у меня сейчас задачка есть: один поток накапливает некоторую статистику, второй поток время от времени ее должен забирать. Обновление статистики — не атомарная, к сожалению, операция. Поэтому блок данных, где текущая статистика лежит, должен защищаться каким-то образом.

По-твоему, здесь нужно перейти на использование CSP или чего-то подобного? При том, что первый поток вообще не знает, когда именно собираемая им статистика потребуется второму потоку (может через секунду, может через час).

eao197 ★★★★★
()
Ответ на: комментарий от pon4ik

но кроме как более низкоуровневыми средствами, я слабо представляю эффективную релизацию multiple reader single writer без shared_lock

А это уже зависит от конкретной задачи. Если чтение/запись сделаны быстрыми сами по себе и без дополнительных вызовов, то и нет особой надобности именно в shared_mutex, без него даже быстрее может быть. Ну, а если они медленные, то сначала стоит над этим поработать, попробовать вынести тяжелый код, чтоб он никого не держал. И только если не получается так сделать, то уже можно и shared_mutex взять. Потому я и написал, что shared_mutex не заставляет писать плохо, он нужен, но если в голову лезут мысли про shared_recursive_mutex, то стоит сначала их отбросить в сторону и подумать - а можно ли сделать проще.

anonymous
()
Ответ на: комментарий от eao197

просто там, где я сейчас ковыряюсь, это всё даром не нужно. нужно только одно: максимально быстро обрабатывать сетевой трафик. это кастомизация TCP-стека, вынос его из ядра, привязка к ядру процессора, c получением данных через NAPI, без хардварных прерываний на каждый пакет. это очень далеко от шаблонов и каких-то типизированных enum'ов.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.