[multithreading] 경쟁 조건은 무엇입니까?

멀티 스레드 응용 프로그램을 작성할 때 발생하는 가장 일반적인 문제 중 하나는 경쟁 조건입니다.

커뮤니티에 대한 나의 질문은 :

경쟁 조건은 무엇입니까?
그것들을 어떻게 감지합니까?
어떻게 처리합니까?
마지막으로, 당신은 어떻게 발생하지 않도록합니까?



답변

경쟁 조건은 둘 이상의 스레드가 공유 데이터에 액세스 할 수 있고 동시에 변경하려고 할 때 발생합니다. 스레드 예약 알고리즘은 언제든지 스레드간에 교환 할 수 있으므로 스레드가 공유 데이터에 액세스하려는 순서를 모릅니다. 따라서, 데이터 변경의 결과는 스레드 스케줄링 알고리즘에 의존한다. 즉, 두 스레드 모두 데이터를 액세스 / 변경하기 위해 “레이싱”하고있다.

하나의 스레드가 “check-then-act”(예 : 값이 X 인 경우 “check”, 값은 X 인 값에 의존하는 무언가를 수행하려면 “act”)를 수행하고 다른 스레드는 “확인”과 “행위”사이. 예 :

if (x == 5) // The "Check"
{
   y = x * 2; // The "Act"

   // If another thread changed x in between "if (x == 5)" and "y = x * 2" above,
   // y will not be equal to 10.
}

요점은 y가 10이 될 수도 있고 다른 스레드가 검사와 작동 사이에서 x를 변경했는지 여부에 따라 무엇이든 될 수 있습니다. 당신은 알 방법이 없습니다.

경쟁 조건이 발생하지 않도록하려면 일반적으로 한 번에 하나의 스레드 만 데이터에 액세스 할 수 있도록 공유 데이터를 잠그십시오. 이것은 다음과 같은 것을 의미합니다.

// Obtain lock for x
if (x == 5)
{
   y = x * 2; // Now, nothing can change x until the lock is released.
              // Therefore y = 10
}
// release lock for x


답변

공유 자원에 액세스하는 멀티 스레드 (또는 병렬) 코드가 예기치 않은 결과를 초래할 수있는 경우 “경합 상태”가 존재합니다.

이 예제를 보자 :

for ( int i = 0; i < 10000000; i++ )
{
   x = x + 1; 
}

이 코드를 한 번에 5 개의 스레드로 실행하면 x WOULD 값은 50,000,000이되지 않습니다. 실제로는 실행마다 다릅니다.

각 스레드가 x 값을 늘리려면 다음을 수행해야하기 때문입니다.

x의 값을 구합니다
이 값에 1을 더하십시오
이 값을 x에 저장

모든 스레드는 언제든지이 프로세스의 모든 단계에있을 수 있으며 공유 리소스가 관련 될 때 서로 밟을 수 있습니다. x의 상태는 x를 읽는 시간과 다시 쓰는 시간 동안 다른 스레드에 의해 변경 될 수 있습니다.

스레드가 x 값을 검색하지만 아직 저장하지 않았다고 가정 해 봅시다. 다른 스레드도 동일한 값의 x를 검색 할 수 있으며 (스레드가 아직 변경되지 않았기 때문에) 동일한 값 (x + 1)을 다시 x에 저장합니다 !

예:

스레드 1 : x를 읽고 값은 7입니다.
스레드 1 : x에 1을 더하면 값은 8입니다.
스레드 2 : x를 읽고 값은 7입니다.
스레드 1 : x를 8로 저장
스레드 2 : 1을 x에 더하고 값은 8입니다.
스레드 2 : x에 8을 저장

공유 리소스에 액세스하는 코드 앞에 일종의 잠금 메커니즘 을 사용하여 경쟁 조건을 피할 수 있습니다 .

for ( int i = 0; i < 10000000; i++ )
{
   //lock x
   x = x + 1; 
   //unlock x
}

여기서 대답은 매번 50,000,000으로 나타납니다.

잠금에 대한 자세한 내용은 뮤텍스, 세마포어, 중요 섹션, 공유 리소스를 검색하십시오.


답변

경쟁 조건이란 무엇입니까?

오후 5시에 영화를 보러 갈 계획입니다. 오후 4시에 티켓의 가용성에 대해 문의하십시오. 담당자는 이용 가능하다고 말합니다. 공연 5 분 전에 휴식을 취하고 티켓 창에 도착하십시오. 나는 당신이 무슨 일이 일어 났는지 추측 할 수 있다고 확신합니다 : 그것은 풀 하우스입니다. 여기서 문제는 점검과 조치 사이의 기간에있었습니다. 당신은 4시에 물었고 5시에 행동했습니다. 그동안 누군가 다른 사람이 티켓을 bb습니다. 이는 경쟁 조건입니다. 특히 경쟁 조건에 대한 “확인 후 행동”시나리오입니다.

당신은 그들을 어떻게 감지합니까?

종교적 코드 검토, 다중 스레드 단위 테스트. 바로 가기가 없습니다. 여기에는 Eclipse 플러그인이 거의 없지만 아직 안정된 것은 없습니다.

어떻게 처리하고 방지합니까?

가장 좋은 방법은 부작용이없고 상태 비 저장 기능을 만들고 가능한 한 불변을 사용하는 것입니다. 그러나 이것이 항상 가능한 것은 아닙니다. 따라서 java.util.concurrent.atomic을 사용하면 동시 데이터 구조, 적절한 동기화 및 액터 기반 동시성이 도움이됩니다.

동시성에 가장 적합한 리소스는 JCIP입니다. 위의 설명에 대한 자세한 내용은 여기를 참조하십시오 .


답변

경쟁 조건과 데이터 경쟁간에 중요한 기술적 차이가 있습니다. 대부분의 답변은 이러한 용어가 동일하다고 가정하지만 그렇지는 않습니다.

데이터 레이스는 2 개의 명령어가 동일한 메모리 위치에 액세스 할 때 발생하며, 이러한 액세스 중 적어도 하나는 쓰기이며 이러한 액세스 중 순서 전에 발생 하지 않습니다 . 이제 주문하기 전에 발생하는 것은 많은 논쟁의 대상이지만 일반적으로 동일한 잠금 변수의 ulock-lock 쌍과 동일한 조건 변수의 대기 신호 쌍은 사전 순서를 유발합니다.

경쟁 조건은 의미 상 오류입니다. 잘못된 프로그램 동작으로 이어지는 이벤트의 타이밍 또는 순서에 발생하는 결함입니다 .

많은 경쟁 조건이 데이터 경쟁으로 인해 발생할 수 있지만 실제로는 그렇지 않습니다. 사실, 데이터 경쟁과 경쟁 조건은 서로에게 필요한 조건도 충분하지도 않습니다. 블로그 게시물은 간단한 은행 거래 예제를 통해 차이점을 잘 설명합니다. 차이점을 설명하는 또 다른 간단한 예가 있습니다.

이제 용어를 정리 했으므로 원래 질문에 대답하려고합니다.

경쟁 조건이 의미 상 버그라는 점을 감안할 때 일반적인 버그 감지 방법은 없습니다. 일반적인 경우에 올바른 프로그램 동작과 잘못된 프로그램 동작을 구별 할 수있는 자동화 된 Oracle을 보유 할 방법이 없기 때문입니다. 레이스 감지는 결정 불가능한 문제입니다.

반면에 데이터 레이스는 정확성과 반드시 ​​관련이없는 정확한 정의를 가지므로이를 감지 할 수 있습니다. 다양한 데이터 레이스 탐지기 (정적 / 동적 데이터 레이스 감지, 잠금 기반 데이터 레이스 감지, 이전 데이터 레이스 감지, 하이브리드 데이터 레이스 감지)가 있습니다. 최첨단 동적 데이터 레이스 검출기는 ThreadSanitizer 로, 실제로 매우 잘 작동합니다.

일반적으로 데이터 경쟁을 처리하려면 공유 데이터에 대한 액세스 사이 (개발 중 또는 위에서 언급 한 도구를 사용하여 감지 된 경우) 사이의 에지를 유발하는 프로그래밍 규칙이 필요합니다. 이것은 잠금, 조건 변수, 세마포어 등을 통해 수행 될 수 있습니다. 그러나 구성에 의한 데이터 경쟁을 피하는 메시지 공유 (공유 메모리 대신)와 같은 다른 프로그래밍 패러다임을 사용할 수도 있습니다.


답변

표준 정렬 정의는 ” 두 개의 스레드가 동시에 메모리의 동일한 위치에 액세스하고 액세스 중 하나 이상이 쓰기 “인 경우입니다. 상황에서 “리더”스레드는 “레이스를이기는”스레드에 따라 이전 값 또는 새 값을 얻을 수 있습니다. 이것이 항상 버그는 아니지만 실제로는 털이 많은 저수준 알고리즘이 의도적으로이를 수행하지만 일반적으로 피해야합니다. @Steve Gury는 언제 문제가 될 수 있는지에 대한 좋은 예입니다.


답변

경쟁 조건은 일종의 버그이며 특정 시간적 조건에서만 발생합니다.

예 : 두 개의 스레드 A와 B가 있다고 가정하십시오.

스레드 A에서 :

if( object.a != 0 )
    object.avg = total / object.a

스레드 B에서 :

object.a = 0

객체 A를 검사 한 직후에 스레드 A가 선점되면 a는 null이 아니고 B는 수행 a = 0하고 스레드 A가 프로세서를 확보하면 “0으로 나누기”를 수행합니다.

이 버그는 스레드 A가 if 문 바로 뒤에 선점 된 경우에만 발생하지만 매우 드물지만 발생할 수 있습니다.


답변

경쟁 조건은 소프트웨어와 관련이있을뿐만 아니라 하드웨어와도 관련이 있습니다. 실제로이 용어는 처음에 하드웨어 산업에서 만들어졌습니다.

Wikipedia 에 따르면 :

이 용어 는 출력영향
미치기 위해 서로 경주 하는 두 신호 의 개념에서 비롯됩니다 .

논리 회로의 경쟁 조건 :

여기에 이미지 설명을 입력하십시오

소프트웨어 산업은이 용어를 수정하지 않고 이해하기가 조금 어려웠습니다.

소프트웨어 세계에 매핑하려면 대체를 수행해야합니다.

  • “two signal”=> “두 스레드”/ “두 프로세스”
  • “출력에 영향을 미침”=> “일부 공유 상태에 영향을 미침”

따라서 소프트웨어 산업의 경쟁 조건은 “일부 공유 상태에 영향을 미치기”위해 서로 경쟁하는 “두 스레드”/ “두 프로세스”를 의미하며, 공유 상태의 최종 결과는 일부 미묘한 타이밍 차이에 따라 달라집니다. 스레드 / 프로세스 실행 순서, 스레드 / 프로세스 스케줄링 등