언제 mutex 대신 spinlock을 사용해야합니까?


294

둘 다 같은 일을하고 있다고 생각합니다. 동기화에 사용할 것을 어떻게 결정합니까?



11
뮤텍스와 세마포어는 같은 것이 아니기 때문에 이것이 중복이라고 생각하지 않습니다. 참조 된 기사의 답변에이 내용이 올바르게 나와 있습니다. 자세한 내용은 참조하십시오 barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore
nanoquack

답변:


729

이론

이론적으로 스레드가 뮤텍스를 잠그려고 시도하고 성공하지 못하면 뮤텍스가 이미 잠겨 있기 때문에 잠자기 상태가되어 즉시 다른 스레드를 실행할 수 있습니다. 그것은 깨어날 때까지 계속 잠 들어 있는데, 이것은 이전에 잠금 장치를 잡고 있던 스레드에 의해 뮤텍스가 잠금 해제되는 경우입니다. 스레드가 spinlock을 잠그려고 시도하고 실패하면 마지막으로 성공할 때까지 계속해서 잠금을 다시 시도합니다. 따라서 다른 스레드가 대신 사용될 수는 없습니다 (단, 현재 스레드의 CPU 런타임 퀀텀이 초과되면 운영 체제는 다른 스레드로 강제 전환합니다).

문제

뮤텍스의 문제점은 스레드를 휴면 상태로 만들고 다시 깨우는 것이 비용이 많이 드는 작업이므로 상당히 많은 CPU 명령이 필요하므로 시간이 오래 걸리는 것입니다. 이제 뮤텍스가 매우 짧은 시간 동안 만 잠긴 경우 스레드를 휴면 상태로 전환하고 다시 깨우는 데 소요 된 시간이 스레드가 실제로 잠을자는 시간을 초과하고 스레드가 수행하는 시간을 초과 할 수도 있습니다 spinlock에 지속적으로 폴링하여 낭비했습니다. 반면 스핀 락에 대한 폴링은 지속적으로 CPU 시간을 낭비하고 잠금이 더 오랜 시간 동안 유지되면 훨씬 더 많은 CPU 시간이 낭비되며 스레드가 대신 잠 자면 훨씬 좋을 것입니다.

해결책

단일 코어 / 단일 CPU 시스템에서 스핀 록을 사용하면 스핀 락 폴링이 사용 가능한 CPU 코어 만 차단하고 다른 스레드를 실행할 수없고 다른 스레드를 실행할 수 없으므로 잠금이 작동하지 않기 때문에 일반적으로 의미가 없습니다. 잠금 해제되어 있습니다. IOW, 스핀 락은 해당 시스템에서 CPU 시간 만 낭비하여 실질적인 이점은 없습니다. 스레드가 대신 휴면 상태가되면 다른 스레드가 한 번에 실행되어 잠금을 해제 한 후 다시 깨어 난 후 첫 번째 스레드가 처리를 계속할 수 있습니다.

매우 짧은 시간 동안 만 유지되는 잠금이 많은 멀티 코어 / 멀티 CPU 시스템에서 지속적으로 스레드를 휴면 상태로 만들고 다시 깨우는 데 낭비되는 시간은 런타임 성능을 현저하게 떨어 뜨릴 수 있습니다. 대신 스핀 록을 사용하면 스레드가 전체 런타임 양자를 활용할 수 있습니다 (항상 아주 짧은 시간 동안 만 차단 한 다음 즉시 작업을 계속 수행).

연습

뮤텍스 나 스핀 락이 더 나은지 프로그래머가 미리 알 수 없기 때문에 (예 : 대상 아키텍처의 CPU 코어 수를 알 수 없기 때문에) 운영 체제가 특정 코드가 단일 코어 또는 멀티 코어 환경에서 대부분의 시스템은 뮤텍스와 스핀 락을 엄격하게 구분하지 않습니다. 실제로 대부분의 최신 운영 체제에는 하이브리드 뮤텍스와 하이브리드 스핀 록이 있습니다. 이것이 실제로 무엇을 의미합니까?

하이브리드 뮤텍스는 멀티 코어 시스템에서 처음에는 스핀 락처럼 작동합니다. 스레드가 뮤텍스를 잠글 수없는 경우 뮤텍스가 곧 잠금 해제 될 수 있기 때문에 즉시 잠자기 상태가되지 않으므로 대신 뮤텍스가 먼저 스핀 락처럼 작동합니다. 일정 시간 (또는 재시도 또는 기타 측정 요소) 후에도 여전히 잠금을 얻지 못한 경우에만 실이 잠자기 상태가됩니다. 동일한 코드가 하나의 코어 만있는 시스템에서 실행되는 경우 뮤텍스는 위에서 언급 한 것처럼 유익하지 않습니다.

하이브리드 스핀 록은 처음에는 일반 스핀 록처럼 작동하지만 너무 많은 CPU 시간을 낭비하지 않기 위해 백 오프 전략이있을 수 있습니다. 일반적으로 스레드를 잠자기 상태로 만들지 않지만 (스핀 록을 사용할 때 발생하지 않기를 원하기 때문에) 스레드를 즉시 중지하거나 일정 시간이 지나면 다른 스레드가 실행되도록 결정할 수 있습니다 따라서 스핀 록이 잠금 해제 될 가능성이 높아집니다 (순수 스레드 스위치는 스레드를 잠자기 상태로 설정 한 후 나중에 다시 깨우는 방법보다 저렴합니다).

요약

의심스러운 경우 뮤텍스를 사용하는 것이 일반적으로 더 나은 선택이며 가장 현대적인 시스템은 매우 짧은 시간 동안 스핀 록을 허용합니다. 스핀 락을 사용하면 때로는 성능을 향상시킬 수 있지만 특정 조건과 의심 스러울 경우에만 현재 스핀 락이 유리한 프로젝트를 진행하고 있지 않다는 사실을 알 수 있습니다. 스핀 락 또는 뮤텍스를 내부적으로 사용할 수있는 자체 "잠금 개체"를 사용하는 것을 고려할 수 있습니다 (예 : 이러한 동작은 이러한 개체를 만들 때 구성 가능). 처음에 어디서나 뮤텍스를 사용하고 스핀 락을 사용하면 실제로는 도움을 요청하고 결과를 비교하고 (예 : 프로파일 러 사용) 두 경우 모두 테스트해야합니다.

업데이트 : iOS에 대한 경고

실제로 iOS에 국한되지는 않지만 iOS는 대부분의 개발자가이 문제에 직면 할 수있는 플랫폼입니다. 시스템에 스레드 스케줄러가있는 경우 우선 순위가 아무리 낮아도 스레드가 실행될 가능성을 보장하지 않습니다. 스핀 락은 영구 교착 상태로 이어질 수 있습니다. iOS 스케줄러는 서로 다른 클래스의 스레드를 구별하고 하위 클래스의 스레드는 상위 클래스의 스레드도 실행하지 않을 경우에만 실행됩니다. 이에 대한 백 오프 전략이 없으므로, 고급 스레드를 영구적으로 사용할 수있는 경우, 낮은 클래스 스레드는 CPU 시간을 얻지 않으므로 작업을 수행 할 기회가 없습니다.

문제는 다음과 같이 나타납니다. 코드가 낮은 prio 클래스 스레드에서 spinlock을 획득하고 해당 잠금 중간에있는 동안 퀀텀 시간이 초과되어 스레드 실행이 중지됩니다. 이 스핀 록을 다시 해제 할 수있는 유일한 방법은 낮은 prio 클래스 스레드가 다시 CPU 시간을 얻는 경우이지만 이것이 보장되지는 않습니다. 지속적으로 실행하려는 몇 개의 높은 prio 클래스 스레드가있을 수 있으며 작업 스케줄러가 항상 우선 순위를 지정합니다. 그중 하나가 스핀 락을 가로 질러 달려 가려고 시도 할 수 있습니다. 물론 불가능하며 시스템은 그것을 생산할 것입니다. 문제는 다음과 같습니다. 생성 된 스레드를 즉시 다시 실행할 수 있습니다! 잠금을 유지하는 스레드보다 높은 prio를 가지면 잠금을 유지하는 스레드는 CPU 런타임을 얻을 수 없습니다.

뮤텍스에서이 문제가 발생하지 않는 이유는 무엇입니까? 높은 prio 쓰레드가 뮤텍스를 얻을 수 없을 때, 뮤텍스를 얻지 못하고 조금 회전하지만 결국 잠자기 상태가됩니다. 잠자는 스레드는 잠금 해제중인 뮤텍스와 같은 이벤트와 같은 이벤트에 의해 깨어날 때까지 실행할 수 없습니다. Apple은이 문제를 알고 있으므로 OSSpinLock결과적으로 더 이상 사용되지 않습니다 . 새로운 자물쇠를 호출 os_unfair_lock합니다. 이 잠금은 다른 스레드 우선 순위 클래스를 인식하므로 위에서 언급 한 상황을 피합니다. iOS 프로젝트에서 spinlocks를 사용하는 것이 좋다고 확신하는 경우 해당 것을 사용하십시오. 멀리 떨어져OSSpinLock! 그리고 어떤 상황에서도 iOS에서 자신의 스핀 락을 구현하지 마십시오! 의심스러운 경우 뮤텍스를 사용하십시오! macOS는 다른 스레드 스케줄러를 사용하므로 CPU 시간에 스레드 (낮은 prio 스레드)가 "건조"할 수없는 다른 스레드 스케줄러가 있으므로 여전히 동일한 상황이 발생하여 매우 열악하게됩니다. 따라서 성능 OSSpinLock은 macOS에서도 더 이상 사용되지 않습니다.


3
훌륭한 설명 ... spinlock i에 대한 의문이 있습니다. eSR에서 spinlock을 사용할 수 있습니까? 만약 그렇지 않다면
haris

4
@Mecki 내가 실수하지 않으면 시간 슬라이싱은 단일 프로세서 시스템에서만 발생한다고 대답했습니다. 이것은 정확하지 않습니다! 단일 프로세서 시스템에서 스핀 잠금을 사용할 수 있으며 시간 퀀텀이 만료 될 때까지 회전합니다. 그런 다음 우선 순위가 동일한 다른 스레드를 인계 할 수 있습니다 (멀티 프로세서 시스템에서 설명한 것과 동일).
fumoboy007

7
@ fumoboy007 "시간 양자가 만료 될 때까지 회전합니다."// 이는 단일 혜택없이 전혀 CPU 시간 / 배터리 전력을 낭비한다는 것을 의미합니다. 그리고 아니, 난 아무데도 그 타임 슬라이싱은 단일 코어 시스템에서 발생 말했다, 나는이 단일 코어 시스템 밝혔다 타임 슬라이싱이있는 동안, REAL 내가 쓴 것에 대해 병렬 톰 멀티 코어 시스템 (또한 타임 슬라이싱, 아직 관련이없는 내 댓글); 또한 하이브리드 스핀 록이 무엇인지, 왜 단일 및 멀티 코어 시스템에서 잘 작동하는지에 대한 요점을 놓쳤습니다.
Mecki

11
@ fumoboy007 스레드 A가 잠금을 유지하고 중단되었습니다. 스레드 B가 실행되고 잠금을 원하지만 얻을 수 없으므로 회전합니다. 멀티 코어 시스템에서 스레드 A는 스레드 B가 계속 회전하는 동안 다른 코어에서 계속 실행될 수 있으며 잠금을 해제하며 스레드 B는 현재 시간 퀀텀 내에서 계속할 수 있습니다. 단일 코어 시스템에는 잠금을 해제하기 위해 하나의 코어 A 스레드 만 실행할 수 있으며이 코어는 스레드 B 회전에 의해 사용 중입니다. 스레드 B가 타임 퀀텀을 초과하기 전에 스핀 락이 풀릴 수있는 방법이 없으므로 모든 스피닝은 시간 낭비입니다.
Mecki

2
Linux 커널에서 구현 된 스핀 락뮤텍스 에 대한 자세한 내용을 보려면 훌륭한 Linux Device Drivers, Third Edition (LDD3) 5 장 (뮤텍스 : 109 페이지, 스핀 록 : 116 페이지 ) 5 장을 읽는 것이 좋습니다 .
patryk.beza

7

Mecki의 제안에 따라이 기사 에 따라 Alexander Sandler의 블로그에있는 pthread mutex vs pthread spinlock Linux의 Alex는 #ifdef를 사용하여 동작을 테스트하기 위해 spinlock& mutexes를 구현 하는 방법을 보여줍니다 .

그러나 귀하의 관찰에 근거하여 최종 전화를해야합니다. 주어진 예는 고립 된 사례이므로 프로젝트 요구 사항, 환경은 완전히 다를 수 있습니다.


6

또한 특정 환경 및 조건 (예 : 디스패치 레벨> = DISPATCH LEVEL의 창에서 실행 등)에서는 뮤텍스를 사용할 수없고 대신 스핀 록을 사용할 수 있습니다. 유닉스에서도 마찬가지입니다.

여기에 경쟁 stackexchange 유닉스 사이트에서 해당 질문은 : /unix/5107/why-are-spin-locks-good-choices-in-linux-kernel-design-instead-of-something- 더

Windows 시스템에서 발송에 대한 정보 : http://download.microsoft.com/download/e/b/a/eba1050f-a31d-436b-9281-92cdfeae4b45/IRQL_thread.doc


6

Mecki의 답변은 꽤 잘 나타납니다. 그러나 단일 프로세서에서 스핀 락을 사용하면 작업이 인터럽트 서비스 루틴에 의해 잠금을 대기 할 때 의미가있을 수 있습니다. 인터럽트는 제어를 ISR로 전송하여 대기 작업에서 사용할 리소스를 준비합니다. 중단 된 작업을 다시 제어하기 전에 잠금을 해제하여 종료됩니다. 스피닝 작업은 스핀 락을 사용할 수 있고 진행됩니다.


2
이 답변에 완전히 동의하지는 않습니다. 단일 프로세서 중 하나 인 작업이 리소스에 대한 잠금을 보유한 경우 ISR은 안전하게 진행할 수 없으며 작업을위한 리소스 잠금 해제를 기다릴 수 없습니다 (자원을 보유한 작업이 중단되었으므로). 이러한 경우, 작업은 인터럽트를 비활성화하여 자체적으로 ISR을 제외시켜야합니다. 물론 이것은 매우 짧은 시간 간격 동안 수행되어야합니다.
user1202136

3

Spinlock 및 Mutex 동기화 메커니즘은 오늘날 매우 일반적입니다.

Spinlock에 대해 먼저 생각해 봅시다.

기본적으로 이는 바쁜 대기 작업이므로 다음 작업을 진행하려면 지정된 잠금이 해제 될 때까지 기다려야합니다. 개념적으로 매우 간단하지만 구현하는 것은 아닙니다. 예를 들어 : 잠금이 해제되지 않은 경우 스레드가 스왑 아웃되어 절전 상태가 된 경우 처리해야합니까? 두 스레드가 동시에 액세스를 요청할 때 동기화 잠금을 처리하는 방법은 무엇입니까?

일반적으로 가장 직관적 인 아이디어는 중요한 섹션을 보호하기 위해 변수를 통한 동기화를 처리하는 것입니다. Mutex의 개념은 비슷하지만 여전히 다릅니다. 중점 : CPU 사용률. Spinlock은 CPU 시간을 소비하여 작업을 수행하므로 두 가지의 차이점을 요약 할 수 있습니다.

동종 멀티 코어 환경에서 중요 섹션에 소요되는 시간이 Spinlock을 사용하는 것보다 작은 경우 컨텍스트 전환 시간을 줄일 수 있기 때문에 (일부 시스템 구현은 스위치 중간에 Spinlock이 있기 때문에 단일 코어 비교는 중요하지 않습니다)

Windows에서 Spinlock을 사용하면 스레드가 DISPATCH_LEVEL로 업그레이드되어 경우에 따라 허용되지 않을 수 있으므로 이번에는 Mutex (APC_LEVEL)를 사용해야했습니다.


-6

단일 코어 / 단일 CPU 시스템에서 스핀 록을 사용하면 스핀 락 폴링이 사용 가능한 CPU 코어 만 차단하고 다른 스레드를 실행할 수없고 다른 스레드를 실행할 수 없으므로 잠금이 작동하지 않기 때문에 일반적으로 의미가 없습니다. 잠금 해제되어 있습니다. IOW, 스핀 락은 해당 시스템에서 CPU 시간 만 낭비하므로 실질적인 이점은 없습니다

이것은 잘못이다. 단일 프로세서 시스템에서 스핀 락을 사용하는 경우 CPU 사이클 낭비가 없습니다. 프로세스가 일단 스핀 잠금을 수행하면 선점 기능이 비활성화되므로 회전하는 사람이 없기 때문입니다! 그것을 사용하는 것이 의미가 없다는 것입니다! 따라서 Uni 시스템의 spinlocks는 컴파일 타임에 커널에 의해 preempt_disable로 대체됩니다!


인용 된 것은 여전히 ​​전적으로 사실입니다. 소스 코드의 컴파일 된 결과에 spinlock이 포함되어 있지 않으면 인용 된 내용과 관련이 없습니다. 커널이 컴파일 타임에 스핀 락을 교체한다는 사실을 가정 할 때, 커널 자체에서만 스핀 락에 대해 엄격하게 언급하지 않는 한, 단일 프로세서 일 수도 있고 아닐 수도있는 다른 머신에서 사전 컴파일 될 때 스핀 록은 어떻게 처리됩니까?
Hydranix

"프로세스가 스핀 잠금을 수행하면 선점을 사용할 수 없습니다." 프로세스가 회전 할 때 선점을 비활성화하지 않습니다. 이 경우 스핀 락을 입력하고 떠나지 않고 단일 프로세스로 전체 시스템을 중단시킬 수 있습니다. 스레드가 사용자 공간 대신 ​​커널 공간에서 실행되는 경우 스핀 잠금을 사용하면 실제로 선점을 비활성화 할 수 있지만 여기서 논의되고 있다고 생각하지 않습니다.
콘스탄틴 바이 츠

에서 시간을 컴파일 하여 커널 ?
Shien

@konstantin FYI 스핀 잠금은 커널 공간에서만 사용할 수 있습니다. 스핀 잠금이 수행되면 로컬 프로세서에서 선점을 사용할 수 없습니다.
Neelansh Mittal

분명히 CONFIG_SMP가 활성화 된 커널에 대해 모듈을 컴파일 할 수 없으며 CONFIG_SMP가 비활성화 된 커널에서 동일한 모듈을 실행할 수 없습니다.
Neelansh Mittal
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.