![Linux의 스핀락이란 무엇입니까?](https://linux55.com/image/566/Linux%EC%9D%98%20%EC%8A%A4%ED%95%80%EB%9D%BD%EC%9D%B4%EB%9E%80%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F.png)
Linux 스핀록에 대해 더 알고 싶습니다. 누군가 나에게 설명해 줄 수 있습니까?
답변1
스핀 잠금은 두 개 이상의 프로세스에 의한 동시 수정으로부터 공유 리소스를 보호하는 방법입니다. 리소스 수정을 시도하는 첫 번째 프로세스는 잠금을 "획득"하고 계속 진행하여 리소스에 대해 필요한 작업을 수행합니다. 이후에 잠금을 획득하려고 시도하는 다른 모든 프로세스는 중지되며 첫 번째 프로세스가 잠금을 해제할 때까지 대기하므로 스핀 잠금이라는 이름이 붙습니다.
Linux 커널은 특정 주변 장치로 데이터를 보낼 때와 같이 다양한 방법으로 스핀록을 사용합니다. 대부분의 하드웨어 주변 장치는 여러 개의 동시 상태 업데이트를 처리하도록 설계되지 않았습니다. 두 가지 다른 수정 사항을 적용해야 하는 경우 하나는 다른 하나를 엄격히 따라야 하며 중복될 수 없습니다. 스핀 잠금은 한 번에 하나의 수정만 이루어지도록 필요한 보호 기능을 제공합니다.
스핀 잠금은 스핀으로 인해 해당 스레드의 CPU 코어가 다른 작업을 수행하는 것을 방해하기 때문에 문제가 됩니다. Linux 커널은 그 아래에서 실행되는 사용자 공간 프로그램에 멀티태스킹 서비스를 제공하지만 이 일반적인 멀티태스킹 기능은 커널 코드로 확장되지 않습니다.
이것은 변화하고 있으며 대부분의 Linux 존재에서 그랬습니다. Linux 2.0 이전에는 커널이 거의 순전히 단일 작업 프로그램이었습니다. CPU가 커널 코드를 실행할 때마다 BKL(Big Kernel Lock)이라고 하는 모든 공유 리소스를 보호하는 스핀 잠금이 있었기 때문에 하나의 CPU 코어만 사용되었습니다. Linux 2.2부터 BKL은 점차적으로 여러 개의 독립적인 잠금으로 분해되었으며, 각 잠금은 보다 집중된 리소스 클래스를 보호합니다. 오늘날 커널 2.6에는 BKL이 여전히 존재하지만 더 세분화된 잠금으로 쉽게 이동할 수 없는 아주 오래된 코드에서만 사용됩니다. 오늘날 멀티 코어 시스템에서는 각 CPU가 유용한 커널 코드를 실행하게 될 가능성이 높습니다.
Linux 커널에는 범용 멀티태스킹 기능이 없기 때문에 BKL 인수분해의 유용성이 제한됩니다. 커널 스핀 잠금에서 CPU 코어 회전이 차단되면 잠금이 해제될 때까지 작업을 재할당할 수 없으며 다른 작업을 수행할 수 없습니다. 잠금이 해제될 때까지 그냥 앉아서 회전합니다.
워크로드가 각 코어가 항상 단일 스핀록을 기다리는 정도라면 스핀록은 거대한 16코어 상자를 단일 코어 상자로 효과적으로 전환할 수 있습니다. 이는 Linux 커널 확장성의 주요 제한 사항입니다. CPU 코어를 2개에서 4개로 늘리면 Linux 시스템 속도가 거의 두 배로 빨라질 수 있지만, 16개에서 32개로 가는 대부분의 작업 부하에서는 두 배가 되지 않을 것입니다.
답변2
스핀 잠금은 프로세스가 제거할 잠금을 지속적으로 폴링하는 경우입니다. 프로세스가 (보통) 불필요하게 주기를 소비하기 때문에 이는 나쁜 것으로 간주됩니다. 이는 Linux에만 국한된 것이 아니라 일반적인 프로그래밍 패턴입니다. 이는 일반적으로 나쁜 습관으로 간주되지만 실제로는 올바른 솔루션입니다. 어떤 경우에는 스케줄러 사용 비용(CPU 주기 측면에서)이 스핀 잠금 주기 비용이 지속될 것으로 예상되는 횟수보다 높습니다. .
스핀 잠금의 예:
#!/bin/sh
#wait for some program to clear a lock before doing stuff
while [ -f /var/run/example.lock ]; do
sleep 1
done
#do stuff
일반적으로 스핀락을 방지하는 방법이 있습니다. 이 특정 예에는 다음과 같은 Linux 도구가 있습니다.inotify기다려(보통 기본적으로 설치되지 않습니다.) C로 작성된 경우 다음을 사용할 수 있습니다.inotifyLinux에서 제공하는 API입니다.
inotifywait를 사용한 동일한 예는 스핀락 없이 동일한 작업을 수행하는 방법을 보여줍니다.
#/bin/sh
inotifywait -e delete_self /var/run/example.lock
#do stuff
답변3
스레드가 잠금을 획득하려고 시도할 때 실패하면 세 가지 일이 발생할 수 있습니다. 시도하고 차단할 수 있고, 시도하고 계속할 수 있으며, 시도한 다음 절전 모드로 전환하여 어떤 일이 발생하면 운영 체제에 깨우라고 지시할 수 있습니다. .
이제는 시도하고 차단하는 것보다 시도하고 계속하는 데 훨씬 적은 시간이 걸립니다. "시도하고 계속하기"에 1시간 단위가 걸리고 "시도하고 차단"에 100시간 단위가 걸린다고 잠시 가정해 보겠습니다.
이제 스레드가 잠금을 유지하는 데 평균 4단위의 시간이 걸린다고 가정해 보겠습니다. 100개를 기다리는 것은 낭비입니다. 따라서 "시도하고 계속하기" 루프를 작성할 수 있습니다. 네 번째 시도에서는 일반적으로 잠금 장치를 얻습니다. 이것은 스핀 잠금입니다. 스레드가 잠금을 획득할 때까지 제자리에서 계속 회전하기 때문에 이렇게 부릅니다.
추가적인 안전 조치는 루프 실행 횟수를 제한하는 것입니다. 예를 들어, for 루프 실행을 6번 수행하고 실패하면 "시도하고 차단"합니다.
하나의 스레드가 잠금을 영원히 유지한다는 것을 알고 있다면(예: 200개 단위) 시도하고 계속할 때마다 컴퓨터 시간을 낭비하게 됩니다.
따라서 결국 스핀락은 매우 효율적일 수도 있고 매우 낭비적일 수도 있습니다. 잠금을 유지하는 데 걸리는 "일반적인" 시간이 "시도 및 차단"하는 데 걸리는 시간보다 길면 낭비입니다. 잠금이 유지되는 일반적인 시간이 "시도 및 차단" 시간보다 훨씬 낮을 때 효과적입니다.
Ps: 스레드에 대해 읽어볼 수 있는 책은 "A Thread Primer"입니다. 아직 찾을 수 있다면요.
답변4
스핀록은 스케줄러를 비활성화하고 잠금이 획득된 특정 코어를 중단(irqsave 변형)하여 작동하는 잠금입니다. 스케줄링을 비활성화한다는 점에서 뮤텍스와 다르므로 스핀 잠금을 유지하는 동안 스레드만 실행할 수 있습니다. 뮤텍스를 사용하면 예약된 동안 우선순위가 더 높은 다른 스레드를 예약할 수 있지만 동시에 보호된 부분을 실행할 수는 없습니다. spinlock은 멀티태스킹을 비활성화하므로 spinlock을 획득한 다음 뮤텍스를 획득하려는 다른 코드를 호출할 수 없습니다. spinlock 섹션 내의 코드는 절대로 절전 모드에 있어서는 안 됩니다(코드는 일반적으로 잠긴 뮤텍스나 널 세마포어를 만나면 절전 모드로 전환됩니다).
뮤텍스와의 또 다른 차이점은 스레드가 일반적으로 뮤텍스를 위해 대기하므로 뮤텍스 아래에 대기열이 있다는 것입니다. 그리고 스핀 잠금은 다른 스레드가 실행되어야 하는 경우에도 실행되지 않도록 보장합니다. 따라서 파일 외부에 있고 잠자기 상태인지 확실하지 않은 함수를 호출할 때 스핀 잠금을 유지해서는 안 됩니다.
인터럽트와 스핀 잠금을 공유하려면 irqsave 변형을 사용해야 합니다. 이는 스케줄러를 비활성화할 뿐만 아니라 인터럽트도 비활성화합니다. 이게 말이 돼? 스핀락은 다른 어떤 것도 실행되지 않도록 하여 작동합니다. 인터럽트가 실행되는 것을 원하지 않으면 인터럽트를 비활성화하고 안전하게 중요 섹션에 들어갈 수 있습니다.
멀티 코어 시스템에서 스핀록은 실제로 잠금을 잡고 있는 다른 코어가 해제될 때까지 기다리면서 회전합니다. 이 스핀은 다중 코어 시스템에서만 발생합니다. 단일 코어 시스템에서는 발생하지 않기 때문입니다(스핀 잠금을 누르고 계속하거나 잠금이 해제될 때까지 실행되지 않습니다).
스핀 잠금은 의미가 있는 경우 낭비가 아닙니다. 매우 작은 중요 섹션의 경우 상호 배타적인 작업의 대기열을 할당하는 것은 중요한 작업을 완료하기 위해 몇 마이크로초 동안 스케줄러를 정지시키는 것보다 낭비입니다. 잠자기 작업이 필요하거나 io 작업 중에 잠금을 유지해야 하는 경우(아마도 잠자기) 뮤텍스를 사용하세요. 물론 스핀락을 잠근 다음 인터럽트 내에 해제하려고 시도하지 마십시오. 이것이 작동하는 동안에는 Arduino의 while(flagnotset); 이 경우 세마포어를 사용하십시오.
메모리 트랜잭션 블록의 간단한 상호 배제가 필요한 경우 스핀 잠금을 사용하십시오. 뮤텍스 이전에 여러 스레드를 중지하려면 뮤텍스를 획득한 다음 뮤텍스가 해제되고 동일한 스레드에서 잠기고 해제될 때 계속하려면 우선순위가 가장 높은 스레드를 선택하십시오. 한 스레드에 게시하거나 인터럽트하여 다른 스레드에 넣을 때 세마포어를 포착하세요. 이는 상호 배제를 보장하는 세 가지 약간 다른 방법이며 약간 다른 목적으로 사용됩니다.