다음을 통해 공유


대기 중 스핀 잠금

대기 중인 스핀 잠금 은 경합이 높은 잠금에 적합한 스핀 잠금의 변형입니다. 기존의 큐에 없는 스핀 잠금은 가볍게 경합되거나 더 짧은 기간 잠금에 더 나은 선택입니다.

큐에 대기된 스핀 잠금을 사용할 경우의 이점은 다음과 같습니다.

  1. 프로세서 경합 감소: 기존의 스핀 잠금은 여러 스레드가 잠금 상태 검사 지속적으로 루프(또는 "스핀")하기 때문에 동시에 잠금을 획득하려고 할 때 상당한 프로세서 경합을 초래할 수 있습니다. 이는 특히 다중 프로세서 시스템에서 시스템 성능을 저하시킬 수 있습니다. 대기 중인 스핀 잠금은 스레드를 큐로 구성하여 이를 완화합니다. 스레드가 잠금을 획득하면 다음 줄에서만 잠금을 획득하기 위해 대기하면서 적극적으로 회전합니다. 이렇게 하면 특히 잠금이 더 긴 기간 동안 유지되는 경우 회전 시 낭비되는 CPU 주기가 줄어듭니다.

  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);  

드라이버는 KeAcquireInStackQueuedSpinLock에 대한 포인터로 전달하는 KLOCK_QUEUE_HANDLE 구조를 할당합니다. 드라이버는 스핀 잠금을 해제할 때 KeReleaseInStackQueuedSpinLock 에 대한 포인터로 동일한 구조를 전달합니다.

드라이버는 일반적으로 잠금을 획득할 때마다 스택에 구조를 할당해야 합니다. 드라이버는 해당 디바이스 컨텍스트의 일부로 구조를 할당한 다음 여러 스레드에서 동일한 구조를 공유해서는 안 됩니다.

드라이버는 동일한 스핀 잠금에 대기 중인 스핀 잠금 루틴 및 일반 KeXxxSpinLock 루틴에 대한 호출을 혼합해서는 안됩니다.

드라이버가 이미 IRQL = DISPATCH_LEVEL 경우 KeAcquireInStackQueuedSpinLockAtDpcLevel KeReleaseInStackQueuedSpinLockFromDpcLevel을 대신 호출할 수 있습니다.