잠금에서 경쟁 조건을 방지하는 것은 무엇입니까?


24

데이터 레이스의 기본 사항과 잠금 / 뮤텍스 / 세마포어가 어떻게 데이터 레이스를 방지하는 데 도움이되는지 이해합니다. 그러나 잠금 장치 자체에 "경쟁 상태"가있는 경우 어떻게됩니까? 예를 들어, 동일한 응용 프로그램에 있지만 다른 프로세서에서 실행중인 두 개의 다른 스레드 는 정확히 동시에 잠금을 획득하려고합니다 .

그러면 어떻게됩니까? 이를 방지하기 위해 무엇을해야합니까? 불가능한가, 아니면 평범하지 않은가? 아니면 실제 경쟁 조건이 일어나기를 기다리고 있습니까?


이 질문은 전에 SO에 요청되었습니다 : stackoverflow.com/questions/980521/…
— Doc Brown

그리고 P.SE에 대한 관련 질문 : programmers.stackexchange.com/questions/228827/…
— ratchet freak

잠금을 획득하기 위해 잠금을 획득합니다.) (즉, 잠금에 경쟁 조건이있는 경우 잠금이 올바르게 구현되지 않습니다. 잠금은 상호 배제를 구현하는 구성으로 정의됩니다)
— Tangrs

잠금 장치 작동 방식 에서 중요한 점을 놓쳤습니다 . 그들은 자물쇠에 레이스를 가질 수 없도록 구성되어 있습니다. 그렇지 않으면 완전히 쓸모가 없습니다.
— Zane

답변:


36

불가능한가, 아니면 평범하지 않은가?

불가능한. 예를 들어 하드웨어가 순차적 실행을 보장 하는 비교 및 스왑을 통해 다른 방식으로 구현할 수 있습니다 . 여러 개의 코어 또는 여러 개의 소켓이있는 경우 약간 복잡해지며 코어 사이에 복잡한 프로토콜이 필요 하지만이 모든 것이 처리됩니다.


3
고맙습니다 ... 신 ... 하드웨어에서 처리됩니다 ... (또는 최소한 우리가 만지는 것보다 낮은 수준입니다.)
— corsiKa

2
@gdhoward 나는 그것을 믿을 수 없다 ...이 답변은 5 분도 걸리지 않았으며 그것은 4 백 답변 (주로 SO) 중에서 3 번째로 높은 투표입니다. 그리고 아마도 가장 짧은 것입니다.
— maaartinus

1
@maaartinus-짧고 달콤한 때로는 않습니다.
— Bobson

17

원자 적 "테스트 및 설정"작업의 개념을 연구하십시오.

본질적으로 작업을 나눌 수는 없습니다. 정확히 두 가지 작업을 동시에 수행 할 수는 없습니다. 값을 확인하고, 명확한 경우 설정 한 다음 테스트 할 때와 같이 값을 반환합니다. 잠금 작업에서 테스트 및 설정 후 결과는 항상 "lock == TRUE"입니다. 유일한 차이점은 시작시 설정 또는 설정되지 않은 것입니다.

단일 코어 프로세서의 마이크로 코드 수준에서 이것은 불가분의 하나의 명령이며 구현하기 쉽습니다. 다중 및 다중 코어 프로세서를 사용하면 더 어려워 지지만 프로그래머는 실리콘을 사용하는 똑똑한 사람이 작동하도록 설계되었으므로 걱정할 필요가 없습니다. 본질적으로 그들은 똑같은 일을합니다-멋진 버전의 테스트 및 설정을 원자 명령으로 만듭니다.


2
기본적으로 하드웨어가 본질적으로 어떤 수준에서 순차적이지 않은 경우 다른 방식으로 발생할 수있는 연결을 끊을 수있는 메커니즘이 있습니다.
— Bill Michell

@ BillMichell, 나는 그것을 생각해야했습니다. 실제로, 나는했다; 나는 내 가정이 옳은지 몰랐다.
— Gavin Howard

2

중요한 섹션에 들어가기 위해 코드를 넣으면 경쟁 조건이 상호 배제를 위반하지 않도록 특별히 설계되었습니다.

하드웨어 수준에서 실행되는 대부분의 원자 비교 및 ​​설정 루프가 사용됩니다.

while(!CompareAndSet(&lock, false, true));//busy loop won't continue until THIS thread has set the lock to true
//critical section
CompareAndSet(&lock, true, false);

그 사이에 상호 배제를 가능하게 하는 잘 연구 된 소프트웨어 솔루션 이 있습니다.


1

두 개 이상의 스레드가 동시에 잠금을 획득 할 수는 없습니다. 예를 들어 몇 가지 유형의 동기화 방법이 있습니다.

활성 대기-스핀 잠금

의사 코드 :

1. while ( xchg(lock, 1) == 1); - entry protocole

XCHG는 먼저 "lock"변수에 새 값을 설정 한 다음 이전 값을 반환하는 원자 연산 (x86 아키텍처에 있음)의 예입니다. 원자는 위의 예에서 새 값을 설정하고 이전 값을 반환하는 사이에 중단 될 수 없음을 의미합니다. 원자력-결정 론적 결과.

2. Your code
3. lock = 0; - exit protocol

잠금이 0과 같으면 다른 스레드가 중요한 섹션으로 들어가는 동안 루프가 종료됩니다.

스레드 중단-예를 들어 세마포 계산

이 두 개의 원자 작업을 존재 .Wait()하고 .Signal()변수가 호출 할 수 있습니다 정수 우리가 int currentValue.

Wait():
if (currentValue > 0) currentValue -= 1;
else suspend current thread;

Signal():
If there exists thread suspended by semaphore wake up one of them
Else currentValue += 1;

이제 중요한 섹션 문제를 해결하는 것이 정말 쉽습니다.

의사 코드 :

mySemaphore.Wait();
do some operations - critical section
mySemaphore.Signal();

일반적으로 프로그래밍 스레드 API는 세마포어 임계 ​​섹션에서 최대 동시 스레드를 지정할 수있는 기능을 제공해야합니다. 분명히 멀티 스레드 시스템 (뮤텍스, 모니터, 이진 세마포어 등)에는 더 많은 유형의 동기화가 있지만 위의 아이디어를 기반으로합니다. 스레드 일시 중단을 사용하는 메소드가 활성 대기보다 선호되어야한다고 주장 할 수 있습니다 (cpu가 낭비되지는 않음). 항상 진실은 아닙니다. 스레드가 일시 중단되면 컨텍스트 전환이라는 비싼 작업이 수행됩니다. 그러나 대기 시간이 짧은 경우에는 합리적입니다 (스레드 수 ~ 코어 수).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.