Comments 11
Обычно принято сначала некоторое время пытаться захватить ресурс через атомарные операции, если же это не получается — тогда уходить в «глубокое» ожидание через вызов функций ядра (
PS: хотя правильно, конечно же, не изобретать велосипед, а взять готовую оттестированную реализацию. Многозадачность и синхронизация — это область с очень большим количеством скрытых грабель и крайне сложной отладкой.
Sleep()
). Делается это из-за того, что вызов Sleep()
и им подобным — это очень дорогая операция.PS: хотя правильно, конечно же, не изобретать велосипед, а взять готовую оттестированную реализацию. Многозадачность и синхронизация — это область с очень большим количеством скрытых грабель и крайне сложной отладкой.
+6
А есть URL на готовую оттестированную реализацию, так сказать коробочную?
0
Вот «коробочная» реализация для Windows. Здесь вообще никаких проблем — это часть стандартного рантайма Visual Studio. Хотя я бы все таки рекомендовал SRWLock для нормальных систем (тем более, что Windows — для отладки и тестирования), а для XP можно уже и собственный велосипед оставить (ей все равно недолго жить осталось).
А здесь — для QNX.
А здесь — для QNX.
0
Если все равно используются платформо-зависимые примитивы, то почему бы для Windows не использовать SRWLock-и?
Кроме того, Sleep(0) делает не совсем то, что думает большинство людей, использующих эту функцию. Если хочется отдать квант, следует использовать SwitchToThread. Если ресурс не удается захватить, а SwitchToThread возвращает FALSE, то, в зависимости от требований к задеркам (latency) и энергоэффективности, можно использовать Sleep в надежде, что поток, захвативший ресурс таки проснется и освободит его.
Ну и еще замечание. InterlockedCompareExchange и InterlockedExchangeAdd (почему ExchangeAdd с 1 и -1, а не Increment/Decrement?) вставляют полный барьер памяти, что может существенно повлиять на производительность. В идеале стоило бы расставить полубарьеры.
Кроме того, Sleep(0) делает не совсем то, что думает большинство людей, использующих эту функцию. Если хочется отдать квант, следует использовать SwitchToThread. Если ресурс не удается захватить, а SwitchToThread возвращает FALSE, то, в зависимости от требований к задеркам (latency) и энергоэффективности, можно использовать Sleep в надежде, что поток, захвативший ресурс таки проснется и освободит его.
Ну и еще замечание. InterlockedCompareExchange и InterlockedExchangeAdd (почему ExchangeAdd с 1 и -1, а не Increment/Decrement?) вставляют полный барьер памяти, что может существенно повлиять на производительность. В идеале стоило бы расставить полубарьеры.
0
del
0
Вызов Sleep(0), даже при замене на SwitchToThread — плохое решение. Переход на уровень ядра и переключение контекста обходятся очень дорого. А тут оно может выполнится много раз. Почему бы не воспользоваться событиями для WinAPI и condition variables для POSIX?
+1
Полностью согласен, просто не стал повторять то, что уже сказано в первом комментарии. Хорошая практика — попробовать «покрутиться» на переменной и попытаться захватить ее без смены контекста. Если все равно занято — то выйти из busy-wait-а и не жечь впустую процессор.
Я, кстати, не уверен, что будет делать SwitchToThread если нет других потоков, готовых к исполнению на данном процессоре — как бы не перепланировался текущий поток и мы опять не свалились в тупой спинлок (с раундтрипами в ядро).
Я, кстати, не уверен, что будет делать SwitchToThread если нет других потоков, готовых к исполнению на данном процессоре — как бы не перепланировался текущий поток и мы опять не свалились в тупой спинлок (с раундтрипами в ядро).
0
Я не сильно в этом разбираюсь и хотел спросить. Не будет ли ливлок в системе, где приоритет отдается читающим потокам? Ибо написав циклы чтения мы можем ждать какогото изменения. А если увеличить число потоков чтения до большого числа то это только увеличивает такой вариант.
0
Sign up to leave a comment.
Эффективная реализация Readers–writer lock на основе «Interlocked Variable Access»