Pull to refresh

Comments 11

Обычно принято сначала некоторое время пытаться захватить ресурс через атомарные операции, если же это не получается — тогда уходить в «глубокое» ожидание через вызов функций ядра (Sleep()). Делается это из-за того, что вызов Sleep() и им подобным — это очень дорогая операция.

PS: хотя правильно, конечно же, не изобретать велосипед, а взять готовую оттестированную реализацию. Многозадачность и синхронизация — это область с очень большим количеством скрытых грабель и крайне сложной отладкой.
А есть URL на готовую оттестированную реализацию, так сказать коробочную?
Вот «коробочная» реализация для Windows. Здесь вообще никаких проблем — это часть стандартного рантайма Visual Studio. Хотя я бы все таки рекомендовал SRWLock для нормальных систем (тем более, что Windows — для отладки и тестирования), а для XP можно уже и собственный велосипед оставить (ей все равно недолго жить осталось).

А здесь — для QNX.
Стандартная версия под QNX работает медленнее. По крайней мере в моём случае.
Если все равно используются платформо-зависимые примитивы, то почему бы для Windows не использовать SRWLock-и?

Кроме того, Sleep(0) делает не совсем то, что думает большинство людей, использующих эту функцию. Если хочется отдать квант, следует использовать SwitchToThread. Если ресурс не удается захватить, а SwitchToThread возвращает FALSE, то, в зависимости от требований к задеркам (latency) и энергоэффективности, можно использовать Sleep в надежде, что поток, захвативший ресурс таки проснется и освободит его.

Ну и еще замечание. InterlockedCompareExchange и InterlockedExchangeAdd (почему ExchangeAdd с 1 и -1, а не Increment/Decrement?) вставляют полный барьер памяти, что может существенно повлиять на производительность. В идеале стоило бы расставить полубарьеры.
К сожалению SRWLock использовать нельзя из-за поддержки WindowsXP. А вот по поводу SwitchToThread и полу барьеров — хорошее замечание, нужно попробовать.
Вызов Sleep(0), даже при замене на SwitchToThread — плохое решение. Переход на уровень ядра и переключение контекста обходятся очень дорого. А тут оно может выполнится много раз. Почему бы не воспользоваться событиями для WinAPI и condition variables для POSIX?
Полностью согласен, просто не стал повторять то, что уже сказано в первом комментарии. Хорошая практика — попробовать «покрутиться» на переменной и попытаться захватить ее без смены контекста. Если все равно занято — то выйти из busy-wait-а и не жечь впустую процессор.

Я, кстати, не уверен, что будет делать SwitchToThread если нет других потоков, готовых к исполнению на данном процессоре — как бы не перепланировался текущий поток и мы опять не свалились в тупой спинлок (с раундтрипами в ядро).
Я не сильно в этом разбираюсь и хотел спросить. Не будет ли ливлок в системе, где приоритет отдается читающим потокам? Ибо написав циклы чтения мы можем ждать какогото изменения. А если увеличить число потоков чтения до большого числа то это только увеличивает такой вариант.
Sign up to leave a comment.

Articles