
Если вы используете спин-блокировки там, где необходимы мьютексы, вы страдаете от всех проблем с производительностью, которых заслуживаете. Ядро Linux предоставляет фьютексы (быстрые мьютексы в пользовательском пространстве), и вы должны использовать их для блокировки в играх и других приложениях, требующих синхронизации потоков. Не вините ядро Linux, если вы делаете это неправильно, и в результате страдает производительность ваших программ.
написанный Ойвиндом Сётером. опубликовано 2020-01-06 — последний раз отредактировано 07.01.2020
Разработчик Google, который не умеет писать код для Linux, вызвал драму вокруг ядра Linux, которую подхватили некоторые корпоративные блоги.
Google занимается портированием множества игр на платформу Stadia Gaming as a Service на базе Linux. Разработчик Google Stadia Мальте Скарупке попытался выяснить, почему игра, использующая реализацию спин-блокировки, которую он написал, тормозит, и написал довольно длинный и утомительный пост в блоге под названием «Измерение мьютексов, спин-блокировок и насколько плохой планировщик Linux на самом деле», объясняя свои собственные проблемы с планировщик Linux. Сообщение в блоге, обвиняющее планировщик ядер Linux в плохом коде, было широко разглашено некоторыми крупными технологическими публикациями, такими как Tom’s Hardware («Проблемы с портом Google Stadia, обвиняемые в планировщике ядра Linux»).
Изобретатель Linux и главный архитектор Линус Торвальдс ответил двумя длинными и очень подробными сообщениями на форуме реальных технологий. Его первый ответ под названием «Никаких нюансов, только код с ошибками (был: связан с реализацией Spinlock и планировщиком Linux)» начинается с указания на то, что измерения, выполненные разработчиком Google Stadia, бессмысленны:
«
Во-первых, спин-блокировки можно использовать только в том случае, если вы действительно знаете, что их использование не запланировано. Но автор сообщения в блоге, похоже, реализует свои собственные спин-блокировки в пользовательском пространстве, не обращая внимания на то, может ли пользователь блокировки быть запланирован или нет. И код, используемый для заявленного тайминга «блокировка не удерживается», — полная чушь.
Он в основном считывает время до снятия блокировки, а затем считывает его после повторного получения блокировки и утверждает, что разница во времени — это время, когда блокировка не удерживалась. Это просто глупо, бессмысленно и совершенно неправильно.
(..)
Итак, рассматриваемый код — чистый мусор. Вы не можете делать такие спин-блокировки. Или, скорее, вы очень можете делать это таким образом, и когда вы это делаете, вы измеряете случайные задержки и получаете бессмысленные значения, потому что вы измеряете следующее: «У меня много занятой работы, когда все процессы связаны с процессором, и я измеряю случайные точки того, как долго планировщик удерживал процесс на месте «.«
Торвальдс далее уточнил, что правильное решение в Linux — это использовать блокировку с учетом ядра, такую как системный вызов futex:
«Используйте блокировку, в которой вы сообщаете системе, что ждете блокировки, и где поток разблокировки сообщит вам, когда это будет сделано, чтобы планировщик действительно мог работать с вами, а не (случайным образом) работать против вас.
Обратите внимание: когда автор использует реальный std :: mutex, все работает достаточно хорошо и независимо от планировщика. Потому что теперь вы делаете то, что должны делать. Да, временные значения все еще могут быть неверными — неудача — это неудача, но, по крайней мере, теперь планировщик знает, что вы «крутитесь» на блокировке.
Или, если вы действительно хотите использовать спин-блокировки (подсказка: вы этого не делаете), убедитесь, что пока вы удерживаете блокировку, вы не планируете уходить. Для этого вам нужно использовать планировщик реального времени (или быть ядром: внутри спин-блокировки ядра все в порядке, потому что само ядро может сказать: «Эй, я делаю спин-блокировку, вы не можете запланировать меня прямо сейчас»).
(..)
Это не имеет абсолютно ничего общего с задержками когерентности кеша или чем-то подобным. Это все связано с плохо реализованной блокировкой.
Я повторяю: не используйте спин-блокировки в пространстве пользователя, если вы действительно не знаете, что делаете. И имейте в виду, что вероятность того, что вы знаете, что делаете, практически равна нулю.
Есть вполне реальная причина, по которой вам нужно использовать спящие блокировки (например, pthread_mutex и т. Д.).«
Разработчик Google Stadia ответил на этот пост, который побудил Линуса Торвальдса ответить и дополнительно объяснить, что вам вообще не следует использовать спин-блокировки, и размещение большого количества sched_yield в вашем коде не поможет:
«А все потому что вы сделали блокировку в корне неправильно.
(..)
Дело в том, что выполнение собственной блокировки жесткий. Вам действительно нужно понять проблемы, и вам не нужно слишком упрощать вашу модель мира до такой степени, что она фактически больше не описывает реальность.
И нет, любая модель блокировки, использующая sched_yield (), — просто мусор. В самом деле. Если вы используете sched_yield (), вы в основном делаете что-то случайное. Представьте, что произойдет, если вы используете свою «sched_yield ()» для блокировки в игре, и у кого-то есть фоновая задача, которая выполняет сканирование на вирусы, обновляет некоторую системную БД или делает что-то еще в это время?
Да, вы просто потенциально не просто уступили кросс-процессору, вы были привязаны к чему-то совершенно другому, что не имеет ничего общего с вашей блокировкой.
sched_yield () неприемлем для блокировки. КОГДА-ЛИБО. Нет, если вы не во встроенной системе, выполняющей единственную нагрузку на одно ядро.«
Разработчики, которые пишут или портируют игры и другие многопоточные игры, могут кое-что узнать, прочитав всю дискуссию. Разработчик Google Stadia Мальте Скарупке признал, что:
«Это мой первый опыт работы с планировщиком Linux в качестве разработчика.«
Мальте Скарупке о комментарии в своем блоге
1 января 2020 г.
Старые программисты Linux узнали, что спин-блокировкам нет места в коде пользовательского пространства еще в 1990-х годах. Они не имеют никакого отношения к использованию вне ядра, и их следует использовать в ядре только в том случае, если вы абсолютно уверены, что будете ждать очень короткий период времени. Каждый должен когда-нибудь учиться, неудивительно, что более молодым программистам необходимо изучать концепции, которые могут показаться очевидными опытным разработчикам Linux. Также стоит помнить, что Linux это не винда, они очень разные, и вы не можете использовать этот плохой подход в обеих операционных системах и ожидать, что результат будет хорошо работать в Linux. Совершать ошибки и учиться на них — это нормально, но не вините планировщик Linux, если вы делаете это неправильно.