답변:
Spinlock과 세마포어는 주로 네 가지 점에서 다릅니다.
그들이 무엇 1. 스핀 락은 락의 하나의 가능한 구현 ( "회전") 통화 중 대기에 의해 구현되는, 즉 하나입니다. 세마포어는 잠금의 일반화입니다 (또는 반대로 잠금은 세마포의 특수한 경우입니다). 일반적으로 반드시 그런 것은 아니지만 스핀 록은 하나의 프로세스 내에서만 유효하지만 세마포어는 서로 다른 프로세스간에 동기화하는데도 사용할 수 있습니다.
잠금은 상호 배제를 위해 작동합니다. 즉, 한 번에 하나의 스레드가 잠금을 획득하고 코드의 "중요 섹션"을 진행할 수 있습니다. 일반적으로 이것은 여러 스레드가 공유하는 일부 데이터를 수정하는 코드를 의미합니다. 세마포어 카운터를 가지고 있으며, 그 자체에 의해 인수되는 수 하나 개 또는 여러 당신이 그것을 게시하고 (일부 구현에) 최대 허용 값이 무엇인지에 따라 주어진 값 내용에 따라 스레드.
지금까지는 잠금을 최대 값이 1 인 세마포어의 특수한 경우로 간주 할 수 있습니다.
2. 그들이하는 일
위에서 언급 한 바와 같이, 스핀 락은 잠금이므로 상호 배제 (엄격히 1 대 1) 메커니즘입니다. 일반적으로 원자 적 방식으로 메모리 위치를 반복적으로 쿼리 및 / 또는 수정하여 작동합니다. 즉, 스핀 록을 획득하는 것은 "아무것도"를 효과적으로 달성하는 동안 오랫동안 (영원히!) CPU 사이클을 태울 수있는 "바쁜"작업입니다.
이러한 접근 방식에 대한 주된 인센티브는 컨텍스트 스위치가 수백 (또는 수천) 번 회전하는 것과 동일한 오버 헤드가 있다는 사실입니다. 더 효율적입니다. 또한 실시간 애플리케이션의 경우 스케줄러가 나중에 먼 시간에 돌아올 때까지 차단하고 대기하는 것은 허용되지 않을 수 있습니다.
대조적으로 세마포어는 전혀 회전하지 않거나 매우 짧은 시간 동안 만 회전합니다 (시스템 호출 오버 헤드를 방지하기위한 최적화). 세마포어를 획득 할 수 없으면 차단되어 실행할 준비가 된 다른 스레드에 CPU 시간을 제공합니다. 물론 이것은 스레드가 다시 예약되기까지 몇 밀리 초가 지나간다는 것을 의미 할 수 있지만, 이것이 문제가되지 않는다면 (일반적으로 그렇지 않다면) 매우 효율적이고 CPU를 절약하는 접근 방식 일 수 있습니다.
3. 정체
가있는 상태에서 작동하는 방법 스핀 록 또는 잠금없는 알고리즘이 "일반적으로 더 빠르다"거나 "매우 짧은 작업"에만 유용하다는 것은 일반적인 오해입니다 (이상적으로는 동기화 객체를 더 오래 보관해서는 안 됨). 절대적으로 필요한 것보다).
한 가지 중요한 차이점은 혼잡시 다양한 접근 방식이 어떻게 작동 하는지입니다 .
잘 설계된 시스템은 일반적으로 혼잡이 적거나 전혀 없습니다 (즉, 모든 스레드가 정확히 동시에 잠금을 획득하려고하는 것은 아닙니다). 예를 들어, 일반적으로 잠금을 획득 한 다음 네트워크에서 0.5MB의 zip 압축 데이터를로드하고 데이터를 디코딩 및 구문 분석하고 마지막으로 공유 참조를 수정하는 코드를 작성 하지 않습니다 (컨테이너에 데이터 추가 등). 잠금을 해제하기 전에. 대신 공유 리소스 에 액세스 할 목적으로 만 잠금을 획득합니다 .
이것은 내부보다 임계 섹션 외부에서 훨씬 더 많은 작업이 있음을 의미하기 때문에 자연스럽게 임계 섹션 내부에 스레드가있을 가능성이 상대적으로 낮으므로 동시에 잠금을 위해 경쟁하는 스레드가 거의 없습니다. 물론 모든 이제 다음 두 개의 스레드 (이 경우 같은 시간에 잠금을 획득하려고합니다 없습니다 ! 당신이 잠금이 필요하지 않을 일), 그러나 이것은 오히려 "건강한"시스템의 규칙보다 예외 .
이러한 경우 스핀 록 은 잠금 혼잡이 없으면 스핀 록을 획득하는 오버 헤드가 컨텍스트 전환에 대한 수백 / 천 사이클 또는 손실에 대해 1 천 ~ 2 천만 사이클에 비해 단 12 사이클이기 때문에 세마포어보다 훨씬 성능이 뛰어납니다. 시간 조각의 나머지.
반면에 혼잡이 높거나 잠금이 오랜 기간 동안 유지되는 경우 (때로는 어쩔 수없는 경우도 있습니다!) 스핀 록은 아무 것도 달성하기 위해 엄청난 양의 CPU 사이클을 태 웁니다.
세마포어 (또는 뮤텍스)는 다른 스레드가 해당 시간 동안 유용한 작업 을 실행할 수 있도록 허용하므로이 경우 훨씬 더 나은 선택입니다 . 또는 다른 스레드에 유용한 작업이없는 경우 운영 체제가 CPU를 제한하고 열을 줄이고 에너지를 절약 할 수 있습니다.
회전하는 스레드가 가능하게 일어날 수없는 상태 변경 (해제 스레드가 예정되어 있지 때까지, 대한 완전한 시간 대기 낭비로 또한, 단일 코어 시스템에서, 스핀 락은 잠금 혼잡의 존재 매우 비효율적 인 것 ISN을 대기중인 스레드가 실행되는 동안 발생하지 않습니다 !). 따라서 어떤 양의 경합이 주어질 때 잠금을 획득하는 데는 최적의 경우 (릴리스 스레드가 예정된 다음 스레드라고 가정) 약 1 1/2 시간 조각이 걸리며 이는 매우 좋은 동작이 아닙니다.
4. 구현 방법
세마포어는 오늘날 일반적으로 sys_futex
Linux에서 랩핑 됩니다 (선택적으로 몇 번의 시도 후에 종료되는 스핀 록 포함).
스핀 락은 일반적으로 운영 체제에서 제공하는 것을 사용하지 않고 원자 적 작업을 사용하여 구현됩니다. 과거에는 이것은 컴파일러 내장 함수 또는 이식 불가능한 어셈블러 명령어를 사용하는 것을 의미했습니다. 한편 C ++ 11과 C11은 둘 다 언어의 일부로 원자 적 연산을 가지고 있습니다. 따라서 정확한 잠금이없는 코드를 작성하는 일반적인 어려움을 제외하고 이제는 완전히 이식 가능하고 (거의) 잠금없는 코드를 구현할 수 있습니다. 고통없는 방법.
간단히 말해서, 세마포어는 "항복하는"동기화 개체이고, 스핀 록은 '바쁜 대기'개체입니다. (단일 스레드에서 코드 영역을 보호하는 뮤텍스 또는 가드 또는 모니터 또는 중요 섹션과 달리 여러 스레드를 동기화한다는 점에서 세마포어에 약간 더 있습니다)
더 많은 상황에서 세마포어를 사용하지만 매우 짧은 시간 동안 잠그는 스핀 락을 사용합니다. 특히 잠그는 경우 잠금에 비용이 듭니다. 이러한 경우 보호 된 리소스가 잠금 해제되기를 기다리는 동안 잠시 스핀 록하는 것이 더 효율적일 수 있습니다. 너무 오래 회전하면 분명히 성능 저하가 있습니다.
일반적으로 스레드 퀀텀보다 오래 회전하는 경우 세마포어를 사용해야합니다.
Yoav Aviram과 gbjbaanb가 말한 것 이상으로, 또 다른 요점은 단일 CPU 시스템에서는 스핀 잠금을 사용하지 않는 반면 세마포어는 이러한 시스템에서 의미가 있다는 것입니다. 요즘에는 다중 코어 나 하이퍼 스레딩 또는 이와 동등한 장치가없는 시스템을 찾기가 힘들지만 CPU가 하나 뿐인 상황에서는 세마포어를 사용해야합니다. (그 이유는 분명하다고 믿습니다. 단일 CPU가 다른 무언가가 스핀 잠금을 해제하기를 기다리느라 바쁘지만 유일한 CPU에서 실행중인 경우 현재 프로세스 또는 스레드가 선점 될 때까지 잠금이 해제되지 않을 것입니다. O / S, 시간이 걸릴 수 있으며 선점이 발생할 때까지 유용한 일이 발생하지 않습니다.)
저는 커널 전문가는 아니지만 몇 가지 사항이 있습니다.
단일 프로세서 시스템에서도 커널을 컴파일하는 동안 커널 선점이 활성화되어 있으면 스핀 잠금을 사용할 수 있습니다. 커널 선점이 비활성화되면 스핀 잠금 (아마도)이 void 문으로 확장됩니다 .
또한 Semaphore와 Spin-lock을 비교하려고 할 때 세마포는 IPC (유저 랜드)에 사용되는 것이 아니라 커널에서 사용되는 것을 참조한다고 생각합니다.
기본적으로 임계 구간이 작고 (수면 / 기상 오버 헤드보다 작음) 임계 구간이 잠을 잘 수있는 것을 호출하지 않는 경우 스핀 록을 사용해야합니다! 임계 섹션이 더 크고 잠을 잘 수있는 경우 세마포어를 사용해야합니다.
라만 찰로 트라.
Spinlock은 기계에 따른 조립 지침 (예 : 테스트 및 설정)을 사용하여 스레드 간 잠금을 구현하는 것을 말합니다. 스레드가 잠금을 사용할 수있을 때까지 (바쁜 대기) 반복적으로 확인하기 때문에 스레드가 단순히 루프에서 대기 ( "스핀")하기 때문에 스핀 록이라고합니다. 스핀 록은 CPU가 아닌 운영 체제에서 제공하는 기능인 뮤텍스의 대체물로 사용됩니다. 스핀 록은 짧은 시간 동안 잠글 경우 성능이 더 우수하기 때문입니다.
Semaphor는 운영 체제에서 IPC 용으로 제공하는 기능이므로 주 목적은 프로세스 간 통신입니다. 운영 체제에서 제공하는 기능이므로 성능은 헤드 간 잠금을위한 스핀 록만큼 좋지 않습니다 (가능할지라도). 세마포어는 더 오랜 기간 동안 잠그는 데 더 좋습니다.
즉, 어셈블리에서 splinlock을 구현하는 것은 까다 롭고 이식성이 없습니다.
나는 내 관찰을 추가하고 싶습니다. 좀 더 일반적이고 Linux에만 국한되지 않습니다.
메모리 아키텍처 및 프로세서 기능에 따라 다중 코어 또는 다중 프로세서 시스템에서 세마포어를 구현하기 위해 스핀 잠금이 필요할 수 있습니다. 이러한 시스템에서는 두 개 이상의 스레드 / 프로세스가 원하는 경우 경쟁 조건이 발생할 수 있기 때문입니다. 세마포를 획득합니다.
예, 메모리 아키텍처가 다른 모든 액세스를 지연시키는 하나의 코어 / 프로세서에 의한 메모리 섹션 잠금을 제공하고 프로세서가 테스트 및 설정을 제공하는 경우 스핀 잠금없이 세마포어를 구현할 수 있습니다 (그러나 매우 신중하게! ).
그러나 단순하고 저렴한 멀티 코어 시스템이 설계 되었기 때문에 (내가 임베디드 시스템에서 작업 중임) 모든 메모리 아키텍처가 그러한 멀티 코어 / 멀티 프로세서 기능을 지원하는 것은 아니며 테스트 및 설정 또는 이와 동등한 기능 만 지원합니다. 그런 다음 구현은 다음과 같습니다.
세마포어를 해제하려면 다음과 같이 구현해야합니다.
예, OS 수준의 간단한 이진 세마포어의 경우 스핀 잠금 만 대체로 사용할 수 있습니다. 그러나 보호 할 코드 섹션이 매우 작은 경우에만 가능합니다.
앞서 말했듯이 자신의 OS를 구현하는 경우에는주의해야합니다. 이러한 오류를 디버깅하는 것은 재미 있지만 (많은 사람들이 공유하지 않는 내 의견) 대부분 매우 지루하고 어렵습니다.
"뮤텍스"(또는 "상호 배제 잠금")는 두 개 이상의 비동기 프로세스가 독점 사용을 위해 공유 리소스를 예약하는 데 사용할 수있는 신호입니다. "뮤텍스"의 소유권을 얻는 첫 번째 프로세스는 공유 리소스의 소유권도 얻습니다. 다른 프로세스는 첫 번째 프로세스가 "뮤텍스"소유권을 해제 할 때까지 기다려야 획득을 시도 할 수 있습니다.
커널에서 가장 일반적인 잠금 프리미티브는 스핀 락입니다. spinlock은 매우 간단한 단일 홀더 잠금입니다. 프로세스가 스핀 록을 얻으려고 시도하고 사용할 수없는 경우 프로세스는 잠금을 획득 할 수있을 때까지 계속 시도 (회전)합니다. 이 단순함은 작고 빠른 잠금을 만듭니다.
Spinlock은 스레드의 실행 슬라이스 시간이 만료되기 전에 예상 결과가 매우 빨리 발생할 것이라고 확신하는 경우에만 사용됩니다.
예 : 장치 드라이버 모듈에서 드라이버는 하드웨어 레지스터 R0에 "0"을 쓰고 이제 해당 R0 레지스터가 1이 될 때까지 기다려야합니다. H / W는 R0을 읽고 일부 작업을 수행하고 R0에 "1"을 씁니다. 일반적으로 빠르다 (마이크로 초). 이제 회전하는 것이 H / W에 의해 잠자고 중단되는 것보다 훨씬 낫습니다. 물론 회전 중에는 H / W 고장 상태에주의해야합니다!
사용자 응용 프로그램이 회전 할 이유가 전혀 없습니다. 말이 안 돼. 일부 이벤트가 발생하도록 회전하고 해당 이벤트는 빠른 시간 내에 발생하지 않을 수있는 다른 사용자 수준 애플리케이션에 의해 완료되어야합니다. 따라서 사용자 모드에서는 전혀 회전하지 않습니다. 사용자 모드에서 sleep () 또는 mutexlock () 또는 세마포어 lock ()을 사용하는 것이 좋습니다.
에서 어떤 스핀 락과 세마포어의 차이점은 무엇입니까? 에 의해 마치에이 Piechotka :
둘 다 제한된 자원을 관리합니다. 먼저 바이너리 세마포어 (뮤텍스)와 스핀 잠금의 차이점을 설명하겠습니다.
스핀 잠금 은 바쁜 대기를 수행합니다. 즉, 루프를 계속 실행합니다.
while (try_acquire_resource ()); ... 해제();매우 가벼운 잠금 / 잠금 해제를 수행하지만 동일한 리소스에 액세스하려는 다른 스레드가 잠금 스레드를 선점하는 경우 두 번째 스레드는 CPU 퀀텀이 부족할 때까지 리소스를 확보하려고합니다.
반면에 뮤텍스는 다음과 같이 동작합니다.if (! try_lock ()) { add_to_waiting_queue (); 기다림(); } ... 프로세스 * p = get_next_process_from_waiting_queue (); p-> wakeUp ();따라서 스레드가 차단 된 리소스를 얻으려고 시도하면 사용할 수있을 때까지 일시 중단됩니다. 잠금 / 잠금 해제는 훨씬 더 무겁지만 대기는 '자유'와 '공정'입니다.
세마포어 는 여러 번 (초기화에서 알 수 있음) 사용이 허용되는 잠금입니다. 예를 들어 3 개의 스레드가 동시에 리소스를 보유 할 수 있지만 더 이상은 보유 할 수 없습니다. 예를 들어 생산자 / 소비자 문제 또는 일반적으로 대기열에서 사용됩니다.
P (자원 _sem) 자원 = resources.pop () ... resources.push (자원) V (자원 _sem)
spin_trylock
잠금을 획득 할 수없는 경우 오류 코드와 함께 즉시 반환되는. 스핀 록이 항상 그렇게 가혹하지는 않습니다. 그러나을 사용spin_trylock
하려면 응용 프로그램이 그런 방식으로 적절하게 설계되어야합니다 (아마도 보류중인 작업의 대기열, 여기서는 다음 작업을 선택하고 실제 작업은 대기열에 남겨 둡니다).