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


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.