Я пишу многопоточное приложение на С++, где производительность критическая. Мне нужно использовать много блокировки при копировании небольших структур между потоками, для этого я выбрал использование штифтов.
Я провел некоторое исследование и тестирование скорости на этом, и я обнаружил, что большинство реализаций примерно одинаково быстрые:
- Microsoft CRITICAL_SECTION, с установленным значением SpinCount до 1000, насчитывает около 140 единиц времени.
- Реализация этот алгоритм с Microsoft InterlockedCompareExchange насчитывает около 95 единиц времени
- Ive также попытался использовать некоторую встроенную сборку с
__asm {}
, используя что-то вроде этого кода, и она насчитывает около 70 единиц времени, , но я не уверен что был создан правильный барьер памяти.
Изменить: время, указанное здесь, - это время, затрачиваемое на 2 потока для блокировки и разблокировки спин-блокировки в 1 000 000 раз.
Я знаю, что это не большая разница, но поскольку спин-блокировка - это сильно используемый объект, можно подумать, что программисты согласились бы на самый быстрый способ сделать спин-блокировку. Однако поиск в Google приводит к множеству различных подходов. Я бы подумал, что этот вышеупомянутый метод будет самым быстрым, если он будет реализован с использованием встроенной сборки и с использованием команды CMPXCHG8B
вместо сравнения 32-разрядных регистров. Кроме того, необходимо учитывать барьеры памяти, это может быть сделано LOCK CMPXHG8B (я думаю?), что гарантирует "исключительные права" для общей памяти между ядрами. Наконец, [некоторые подсказывают], что для ожидания заняты должны сопровождаться NOP: REP, которые позволят процессорам Hyper-threading переключиться на другой поток, но я не уверен, это правда или нет?
Из моего теста производительности различных шпилек, видно, что нет большой разницы, но для чисто академических целей я хотел бы узнать, какой из них наиболее быстрый. Однако, поскольку у меня очень ограниченный опыт на языке ассемблера и с барьерами памяти, я был бы счастлив, если бы кто-нибудь смог написать код сборки для последнего примера, который я предоставил LOCK CMPXCHG8B и надлежащие барьеры памяти в следующий шаблон:
__asm
{
spin_lock:
;locking code.
spin_unlock:
;unlocking code.
}