Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.220.66.151] |
|
Сообщ.
#1
,
|
|
|
Всем привет!
Возник такой вопрос - вот в std есть куча мьютексов на выбор(вроде в C++14'ом стандарте их 4 - mutex, recursive_mutex, и два таких же с префиксом timed,), меня интересуют ровно два типа мьютексов - std::mutex и std::recursive_mutex. Каково их принципиальное отличие, на уровне ОС Windows? Да, рекурсивный мьютекс очень сильно напоминает CRITICAL_SECTION. Но как я погляжу везде и всюду все используют std::mutex. При этом если сравнивать конкретно Windows синхронизацию, то из книги того же Рихтера, очевидно что Mutex - это объект ядра Windows, а значит ему постоянно приходится переключаться из User Mode в Kernel Mode, что очень медленно, при этом CRITICAL_SECTION - реализована на основе interlocked функций, что существенно повышает производительность(Так как не нужно постоянно переходить в kernel mode). У меня давно возник вопрос - как реализованы мьютексы в пространстве -> std, для той же Windows(есть ли какие нибудь ремарки для них специфичные)? Есть ли об этом в стандарте какие то оговорки? Допустим я пишу какой то критичный по производительности паралельно-выполняющийся алгоритм, и при этом использую std::mutex, какие преимущества я получу, если заменю std::mutex на std::recursive_mutex? При этом, мне не нужно его захватывать больше 1-го раза. И есть ли смысл вообще использовать std::recursive_mutex, если я не хочу его захватывать больше 1 раза? Так же интересует, вдруг мне нужна блокировка на уровне ядра? Я ведь правильно понимаю что для этого нужно использовать обычный std::mutex? Выводы: Правильно ли я понимаю что: std::mutex - Windows mutex - медленный, переключающийся в kernel mode std::recursive_mutex - CRITICAL_SECTION - быстрый, по сравнению с обычным виндовым мьютексом. ??? Отсылки к конкретным пунктам стандарта - очень сильно приветствуются. Спасибо за пояснения. |
Сообщ.
#2
,
|
|
|
Цитата Wound @ Отсылки к конкретным пунктам стандарта - очень сильно приветствуются. Спасибо за пояснения. Не думаю, что это можно будет найти в Стандарте. Речь же идет о "реализации" - ее и нужно копать. Или уже кем-то раскопанное читать, либо самому исследовать исходники STL. Линк |
Сообщ.
#3
,
|
|
|
Цитата JoeUser @ Не думаю, что это можно будет найти в Стандарте. Речь же идет о "реализации" - ее и нужно копать. Или уже кем-то раскопанное читать, либо самому исследовать исходники STL. Фишка основная, которая послужила целью к созданию этой темы, такая -> Вот есть Мьютексы, объекты ядра, и есть Критические секции - не объекты ядра. Первые могут лочить потоки глобально для параллельных процессов, вторые локально - для потоков в рамках одного процесса. Какую структуру данных мне нужно юзать из нового стандарта, чтобы залочить ресурс, использующийся между разными процессами? И будет ли профит, если вдруг я пишу узконаправленное приложение, которое должно обойтись критической секцией, и использую при этом std::recursive_mutex, вместо std::mutex? ИМХО без этого знания - я не могу писать кросплатформенное приложение и опираться на стандартную библиотеку STL. Я хочу выяснить для себя - могу я на нее полагаться при кросплатформенном программировании или нет. Добавлено Если это все оставленно на откуп, то в этом случае std::mutex и std::recursive_mutex могут быть реализованы через критические секции, тогда решая задачу, где мне нужно залочить ресурс между процессами - я внезапно для себя, могу выяснить, что зря я тут юзал std::mutex. А этого бы не хотелось. Хочется каких то гарантий происходящего. |
Сообщ.
#4
,
|
|
|
Wound, повторюсь - твой вопрос вполне понятен.
Стандарт не регламентирует реализацию. |
Сообщ.
#5
,
|
|
|
Цитата JoeUser @ Стандарт не регламентирует реализацию. Ты уверен в этом? Можешь привести раздел стандарта, говорящего об этом? Я имею ввиду конкретно мьютексы. Добавлено Дело в том, что я для себя хочу окончательно этот вопрос решить. И фразы, даже сказанные в повелительном или повествовательном или в финальном тоне - меня не устраивают. Их можно интерпретировать как - Это твое ИМХО. Я же хочу объективности. По возможности. Пусть даже без цитирования стандарта, но с пояснением - почему так. |
Сообщ.
#6
,
|
|
|
Цитата Wound @ Ты уверен в этом? Можешь привести раздел стандарта, говорящего об этом? Я имею ввиду конкретно мьютексы. Уверен. Вообще-то для меня будет откровением если ты приведешь материал из Стандарта, где вообще упоминается M$ Windows, применительно к любому разделу/теме. Лучче поищи дискуссии типа этой. Там как раз обсуждаются реализации. |
Сообщ.
#7
,
|
|
|
Меня интересует конкретно вопрос - std::mutex - очень часто и везде используется, в 95% хелпах, гуглах и остального ты встретишь именно std::mutex. Вопрос - он реализован как критическая секция или нет?
Если он реализован как виндовый Мьютекс, и постоянно лезет в kernel mode - то какой смысл его вообще использовать? Вот мой основной вопрос. А вот std::recursive_mutex очень сильно похож на критическую секцию. Но возникает вопрос - чем std::mutex тогда лучше? Я хочу гарантированного быстродействия, стоит ли мне для этого набирать слово recursive_ или можно обойтись std::mutex, что короче в наборе по крайней мере букв? |
Сообщ.
#8
,
|
|
|
Хотя вот предисловие к последнему стандарту C++17:
Цитата ISO/IEC 14882:2017 specifies requirements for implementations of the C++ programming language. The first such requirement is that they implement the language, so this document also defines C++. Other requirements and relaxations of the first requirement appear at various places within this document. Как видишь - регламентируются требования к реализации языка, но ... читаем между строк ... не сама реализация. Да и глупо это было бы регламентировать реализацию на стопицот осей. |
Сообщ.
#9
,
|
|
|
Цитата JoeUser @ Вообще-то для меня будет откровением если ты приведешь материал из Стандарта, где вообще упоминается M$ Windows, применительно к любому разделу/теме. Речь не о упоминании Windows в стандарте С++. Ты меня не так понял видимо. Ок, я повторюсь и перефразирую: Перед тобой стоит задача распаралелить алгоритм, при этом как можно лучше его оптимизировать. Что ты выберешь - std::mutex или std::recursive_mutex - для защиты общих ресурсов, и почему? Добавлено Цитата Wound @ Что ты выберешь - std::mutex или std::recursive_mutex - для защиты общих ресурсов, и почему? А если нужно защитить ресурс - передаваемый между процессами - какой механизм ты выберешь и почему? |
Сообщ.
#10
,
|
|
|
Цитата Wound @ Вопрос - он реализован как критическая секция или нет? Wound, ты уже третий раз повторяешься. Смотри исходники! К примеру реализация С++ в тулчейне MinGW-w64 имеет две варианта (реализации) с моделями win-theads и posix-threads. И, скорее всего, мьютексы там будут реализованы по разному. Как именно, в исходниках быть должно. Я не смарел - не знаю. |
Сообщ.
#11
,
|
|
|
Цитата JoeUser @ Wound, ты уже третий раз повторяешься. Смотри исходники! Какие исходники? Те что ты привел по ссылке или те что у меня в студии ? Цитата JoeUser @ К примеру реализация С++ в тулчейне MinGW-w64 имеет две варианта (реализации) с моделями win-theads и posix-threads. И, скорее всего, мьютексы там будут реализованы по разному. Как именно, в исходниках быть должно. Я не смарел - не знаю. Ты понимаешь чем отличается виндовый мьютекс от критической секции? Ты понимаешь что акроним - Мьютекс, а это именно уже акроним в Windows системе - означает, это очень медленная операция? Я не знаю понимаешь ли ты это отличия или нет. Фишка даже не в этом, фишка в другом - как мне писать программу, многопоточную - для разных систем - допустим Windows и Linux ? Мне достаточно использовать STL мьютекс или мне так же, как и прежде придется писать код под разные платформы? Добавлено Просто я ожидаю от STL, что получу что то универсальное для любой ОС(ну как Java или там C# -им плевать где запустился - всегда действуют одни и те же правила, ну это в среднем.). В итоге пока не ясно, но по предварительным рассуждениям - я получаю что то узконаправленное под конкретную задачу, привязанную к Linux, потому что Windows Mutex не поддерживаются? А если поддерживаются, то под Винду я получу проседание производительности на порядок? |
Сообщ.
#12
,
|
|
|
Цитата Wound @ Какие исходники? Те что ты привел по ссылке или те что у меня в студии ? Как раз об этом и говорил - о "реализации" Реализация std::recursive_mutex и std::mutex в твоей студии, в migw32, в clang'е - может отличаться реализацией как с использованием мьютексов винды, так и с использованием критических секций. И это предстоит тебе найти в исходниках. Исходники STL студии ты вряд ли найдешь, а для mingw-w64 запросто. Но, коль ты упомянул: Цитата Wound @ ИМХО без этого знания - я не могу писать кросплатформенное приложение и опираться на стандартную библиотеку STL. Но ведь ты желаешь лучшей производительности? Тогда тебе придется выяснить работу std::recursive_mutex и std::mutex и для других осей. Так вот, к примеру, для FreeBSD и Mac OSX крайне желательно использовать clang'овскую реализацию STL, и ее уже исследовать. Бенчмарки там какие-то по этому вопросу пролетали. Добавлено Цитата Wound @ А если поддерживаются, то под Винду я получу проседание производительности на порядок? Вижу два выхода ... или все ж исследовать исходники (или тупо написать наборы тестов), или использовать PIMPL и для венды везде где можно использовать критические секции. Лан, Киля, народ подтянется - возможно кто-то это уже разбирал. Пошел я в анабиоз |
Сообщ.
#13
,
|
|
|
Цитата JoeUser @ Как раз об этом и говорил - о "реализации" Реализация std::recursive_mutex и std::mutex в твоей студии, в migw32, в clang'е - может отличаться реализацией как с использованием мьютексов винды, так и с использованием критических секций. И это предстоит тебе найти в исходниках. Исходники STL студии ты вряд ли найдешь, а для mingw-w64 запросто. Вот видишь, и ты, пусть даже бессознательно, указал на некоторые проблемы. В частности - в разных компиляторах - слово мьютекс - может по разному интерпретироваться, и по разному реализовываться. Цитата JoeUser @ Но ведь ты желаешь лучшей производительности? Да! Цитата JoeUser @ Тогда тебе придется выяснить работу std::recursive_mutex и std::mutex и для других осей. Почему осей? Почему не компиляторов? Какие гарантии что в Майкрософт - std::mutex реализовали через критические секции? Я именно об этом и спрашиваю как бы Цитата JoeUser @ Так вот, к примеру, для FreeBSD и Mac OSX крайне желательно использовать clang'овскую реализацию STL, и ее уже исследовать. Бенчмарки там какие-то по этому вопросу пролетали. Это твое ИМХО, потому что бенчмарки пролетали? Или почему? А в чем отличие от стандарта С++? Цитата JoeUser @ Вижу два выхода ... или все ж исследовать исходники (или тупо написать наборы тестов), или использовать PIMPL и для венды везде где можно использовать критические секции. То есть STL не гарантирует что std::mutex - поможет в лочке ресурсов между процессами? А значит можно сделать вывод что std::mutex реализован через Критические секции? Цитата JoeUser @ Лан, Киля, народ подтянется - возможно кто-то это уже разбирал. Пошел я в анабиоз Да, давай, приятно было пообщаться )) |
Сообщ.
#14
,
|
|
|
JoeUser отчасти прав. Стандарт регламентирует поведение, но не реализацию. Так что MS может сотворить, что ей заблагорассудится, лишь бы поведение соответствовало. Т.к. и мьютексы, и критические секции в WinAPI обладают одинаковым поведением, заюзаны могут быть как те, так и другие.
Теперь анализ постановки задачи. Лично я не думаю, что MS будет использовать мьютексы просто так, потому что захотелось почаще перекидывать программу в ядро. Так что если нет особых причин, скорее всего используются критические секции. Мьютексы от критических секций по поведению отличаются лишь тем, что могут шариться между процессами. Других отличий нет. И тут вот засада: Стандарт не описывает взаимодейсвтие разных программ, он описывает поведение некой виртуальной исполнительной среды C++ в части подготовки и исполнения одной программы. Поэтому в нём не предусмотрено ничего для описания взаимодействия разных программ, даже если они все написаны на C++. Резюме: почти наверняка используются критические секции. У MS не было причин выбирать более медленные мьютексы, т.к. Стандарт не способен задействовать их преимущества. |
Сообщ.
#15
,
|
|
|
JoeUser, вот смотри - есть у тебя std::string и допустим std::endl, ты пишешь кросплатформеную программу, и нужно что то вывести куда то там в файл или в поток - не важно, ты пишешь:
std::cout << "Message" << std::endl И пишешь ты это например на определенном компиляторе, допустим шланг там или МСВС, или ГЦЦ, не важно, но ведь ты ожидаешь что везде и всюду, на любой ОС - ты получишь сообщение "Меssage". Потоки были стандартизированы еще в С++11, ЕМНИП. Отсюда возникает вопрос в использовании - раз они стандартные, значит и к ним какие то требования должны идти, вот я и хочу услышать - что такое std::mutex и чем он принципиально отличается от std::recursive_mutex. Иначе тогда смысл теряется в кроссплатформенном программировании. Я могу юзнуть std::mutex, под Линух, и все тесты написать и все будет в Шоколаде, но под винду моя программа не будет работать вообще, хотя будет написана по последнему слову стандарта. Добавлено Цитата Qraizer @ Резюме: почти наверняка используются критические секции. У MS не было причин выбирать более медленные мьютексы, т.к. Стандарт не способен задействовать их преимущества. То есть std::mutex - это почти наверняка скорее всего критическая секция? Я правильно понимаю? То есть если я использую std::mutex, то в принципе могу не волноваться о том, что производительность просядет за счет переключения в kernel mode, по крайней мере в Windows? Или лучше всегда юзать std::recursive_mutex, и не париться? |
Сообщ.
#16
,
|
|
|
На самом деле уверенность практически 100%. Для межпроцессной синхронизации нужны именованные объекты, для чего в std ничего не предусмотрено. С другой стороны, тебе ничто не мешает написать свои мьютексы, лишь бы их слопал std::lock_guard<>. Требования для этого довольно низки.
|
Сообщ.
#17
,
|
|
|
Цитата Qraizer @ На самом деле уверенность практически 100%. Для межпроцессной синхронизации нужны именованные объекты, для чего в std ничего не предусмотрено. С другой стороны, тебе ничто не мешает написать свои мьютексы, тишь бы их слопал std::lock_guard<>. Требования для этого довольно низки. Я понял, спасибо за разъяснения. В принципе логично. Мне было принципиально услышать аргументы, а не просто "Вот так и все тут". Вопрос решен. |
Сообщ.
#18
,
|
|
|
Цитата Wound @ Разница между std::mutex и std::recursive_mutex всего лишь в одном аспекте поведения: если нитка залочила объект, то в первом случае повторный захват ею этого же объекта приведёт к неопределённому поведению, тогда как во втором случае выполнение продолжится без любой дополнительной блокировки, однако отпустить объект нитка должно столько же раз, сколько захватывала, иначе он так и останется ею занятым. Это поведение строго согласуется и с критическими секциями, и с мьютексами из WinAPI. Первое же поведение ровно такое же, как у семафоров со счётчиком 1, если неопределённое поведение доопределить до дидлука, так что не удивлюсь, если std::mutex реализованы через семафоры. Или лучше всегда юзать std::recursive_mutex, и не париться? |
Сообщ.
#19
,
|
|
|
Я про именованые объекты позабыл просто, и действительно, мьютексов на всех не напасешься, Qraizer, ты навел меня на опрделенную мысль, за что тебе спасибо. Я понял что все std::mutex скорее всего быстрые, да я дебажил std::mutex, но тем не менее хотел понять как лочить объекты между процессами. В принципе логично, что это должен делать тот - кому это нужно. Вопрос исчерпан.
|
Сообщ.
#20
,
|
|
|
Скрытый текст Цитата Wound @ пусть даже бессознательно |