Поделиться через


Очередные spinlock'и

Очередные спин-блокировки являются вариантом спин-блокировок, которые хорошо работают для сильно спорящихся блокировок. Традиционные, необработанные спин-блокировки являются лучшим выбором для блокировок с легкой конкуренцией или более короткой длительности.

Преимущества использования очередной спин-блокировки включают:

  1. Сокращение процессорного соперничества: традиционные спинлоки могут привести к значительному соперничеству за процессорное время, когда несколько потоков пытаются получить блокировку одновременно, так как они непрерывно выполняют цикл, проверяя состояние блокировки. Это может снизить производительность системы, особенно в многопроцессорных системах. Спин-блокировки в очереди снижают воздействие этого путем организации потоков в очередь. Когда поток получает блокировку, только следующая в строке активно спинирует, ожидая получения блокировки. Это сокращает циклы ЦП, потраченные на спиннинг, особенно если блокировка удерживается в течение длительного времени.

  2. Справедливость и избегание голода: одна из проблем с основными спин-замками заключается в отсутствии справедливости; поток может голодать и никогда не получать замок, если другие потоки постоянно получают и освобождают замок. Очередные спин-блокировки устраняют это, гарантируя, что потоки получают блокировку в порядке, в котором они пытались. Эта последовательная обработка предотвращает голодание и гарантирует, что все потоки будут обслуживаться в течение времени.

  3. Масштабируемость. По мере увеличения числа процессоров или ядер в системе эффективность механизмов синхронизации становится критической для производительности. Очередные замки спина более масштабируемы, чем традиционные, поскольку снижают нагрузку на процессоры, минимизируя активное кручение по всем ядрам. Это особенно важно в высокопроизводительных многоядерных системах, где эффективность драйвера может напрямую повлиять на общую производительность системы.

  4. Эффективное использование системных ресурсов: за счет уменьшения ненужного вращения процессора, очереди спин-блокировок позволяют системе эффективнее использовать свои ресурсы. Это не только повышает производительность драйвера устройства, но и оказывает положительное влияние на общую скорость реагирования системы и потребление энергии, что особенно полезно в средах с учетом питания.

  5. Простота и надежность: Несмотря на их преимущества в снижении конфликтов и повышении справедливости, очередные спинлоки скрывают сложность от разработчика. Они предоставляют простой и надежный механизм защиты общих ресурсов без необходимости реализовать сложную логику блокировки. Эта простота снижает вероятность ошибок, связанных с неправильной обработкой блокировки, что повышает надежность драйвера.

Ниже приведен упрощенный фрагмент кода, демонстрирующий описанные операции с блокировкой очереди с использованием спин-блокировки в драйвере режима ядра Windows. В этом примере показано, как объявить и инициализировать спин-блокировку с помощью KeInitializeSpinLock, а затем захватить и освободить блокировку с использованием KeAcquireInStackQueuedSpinLock и KeReleaseInStackQueuedSpinLock соответственно.

KSPIN_LOCK SpinLock;  
KLOCK_QUEUE_HANDLE LockHandle;  

// Initialize the spin lock  
KeInitializeSpinLock(&SpinLock);  

// Assume this function is called in some kind of context where   
// the below operations make sense, e.g., in a device I/O path  

// Acquire the queued spin lock  
KeAcquireInStackQueuedSpinLock(&SpinLock, &LockHandle);  

// At this point, the current thread holds the spin lock.  
// Perform thread-safe operations here.  
    
// ...  

// Release the queued spin lock  
KeReleaseInStackQueuedSpinLock(&LockHandle);  

Драйвер выделяет структуру KLOCK_QUEUE_HANDLE, которую передает с помощью указателя в KeAcquireInStackQueuedSpinLock. Драйвер передает ту же структуру указателем на KeReleaseInStackQueuedSpinLock при освобождении спин-блокировки.

Драйверы обычно должны выделять структуру в стеке каждый раз, когда они получают блокировку. Драйвер не должен выделять структуру как часть контекста устройства, а затем совместно использовать одну и ту же структуру из нескольких потоков.

Драйверы не должны смешивать вызовы к подпрограммам очереди спин-блокировки и обычным подпрограммам KeXxxSpinLock на одной и той же спин-блокировке.

Если драйвер уже находится на уровне IRQL = DISPATCH_LEVEL, он может вместо этого вызывать KeAcquireInStackQueuedSpinLockAtDpcLevel и KeReleaseInStackQueuedSpinLockFromDpcLevel.