발생 가능성이 거의없는 경쟁 조건을 처리해야합니까?


52

메인 스레드가 거의 즉각적으로 UI를 업데이트하고 다른 스레드가 네트워크를 통해 데이터를 폴링하거나 작업을 완료하는 데 5-10 초가 걸리는 GUI 응용 프로그램과 같은 것을 고려해 봅시다.

나는 이것에 대해 많은 다른 대답을 받았지만 어떤 사람들은 그것이 통계 불가능의 경쟁 조건이라면 전혀 걱정하지 말고 다른 사람들은 10-53 % 조차도 있다고 말합니다. 경쟁 조건으로 인해 발생하는 일부 부두 마법에 대한 숫자가 아니라면 이것이 들었습니다. 항상 필요한 스레드에서 잠금을 얻거나 해제하십시오.

당신의 생각은 무엇입니까? 통계적으로 불가능한 상황에서 경쟁 조건을 처리하는 것이 좋은 프로그래밍 관행입니까? 또는 가독성을 방해하기 위해 더 많은 코드 줄을 추가하는 것이 완전히 불필요하거나 비생산적일까요?


21
사람들이 그런 기회를 말할 때 왜 그 숫자를 말하는 사람의 교육에 대해 묻지 않습니까? 그런 숫자로 백업하기 전에 통계에 대한 공식 교육이 필요합니다.
피터 B

27
물리학 자로서 p <1E-140은 p = 0을 의미합니다. 이 우주에서는 일어나지 않을 것입니다. 0.00000000000000000000000000000000000000000000000000001 %는 훨씬 더 큽니다.
MSalters

15
이 경쟁 조건으로 인해 누군가가 기꺼이 앱을 중단 시킬 수 없는지 확인하십시오 . 보안 문제의 원인 일 수 있습니다.
toasted_flakes

27
백만의 기회 중 하나는 10 개 중 9 번 발생합니다.
Kaz Dragon

27
"거의 확실하게 일어날 가능성이 없습니까?" 오전 3시에 프로덕션에서 발생하며 대부분 비용이 많이 듭니다.

답변:


137

실제로 10 ^ 55 이벤트의 1 인 경우이를 코딩 할 필요가 없습니다. 즉, 초당 백만 번 작업을 수행하면 3 * 10 ^ 41 년마다 한 번의 버그가 발생하며 이는 대략 우주 시대의 10 ^ 31 배입니다. 당신의 응용 프로그램이 1 조 조에 달하는 모든 우주에서 한 번만 오류를 가지고 있다면 그것은 아마도 충분히 신뢰할 수 있습니다.

그러나 나는 그 오류가 그와 거의 같지 않다는 것을 매우 많이 걸었다. 오류를 생각할 수 있다면 최소한 때때로 오류가 발생하여 코드를 올바르게 작성하는 것이 좋습니다. 또한 처음부터 스레드를 올바르게 코딩하여 잠금을 적절하게 확보 및 해제하면 나중에 코드를 훨씬 더 유지 보수 할 수 있습니다. 잠재적 인 모든 경쟁 조건을 다시 분석하고 확률을 재 계산하고 재발하지 않도록 자신을 변경해야한다는 변경을 할 때 걱정할 필요가 없습니다.


66
몇 년 전에 읽은 의견을 떠올리지 만 지금은 "다음 번 화요일에 1 백만 번의 기회가 있습니다"라는 메시지를 찾을 수 없습니다. "거의 근처에는 없을 것"이라고 말한 +1.
Bevan

2
베팅에 +1 경쟁 조건을 처리하는 가장 좋은 방법은 경쟁 조건을 제거하는 것입니다.
Blrfl

10
@Bevan "백만 번의 기회는 보통 다음주 화요일입니다"... 추첨을하지 않는 한 :)
dasblinkenlight

22
@dasblinkenlight 그러나 대부분의 복권에서 누군가가 이길 확률은 100 %에 이릅니다 . 누가 예측 하는지 , 지금은 도전입니다.
Bevan

3
@Bevan : 그 의견은 제가 질문을 읽을 때 저의 마음 속에 떠오른 내용입니다. 여기 참조가 있습니다 : blogs.msdn.com/b/larryosterman/archive/2004/03/30/104165.aspx
Doc Brown

69

비용 편익 관점에서 충분한 혜택을 얻을 수있는 경우에만 추가 코드를 작성해야합니다.

예를 들어, 잘못된 스레드가 "경쟁에서 이길"경우에 발생할 수있는 최악의 상황이 정보가 표시되지 않고 사용자가 "새로 고침"을 클릭해야하는 경우 경쟁 조건에 대해주의를 기울이지 않아도됩니다. 많은 코드를 작성하는 것은 중요하지 않은 것을 고칠 가치가 없습니다.

반면에 경쟁 조건으로 인해 은행 계좌간에 잘못된 송금이 발생할 수있는 경우이 문제를 해결하기 위해 작성해야하는 코드의 양에 상관없이 경쟁 조건으로부터 보호해야합니다.


20
+1 : "실패한 것처럼 보이는 실패"와 "성공한 것처럼 보이는 실패"를 구분합니다. 도메인에 따라 잘못된 정보가 훨씬 더 심각합니다.
deworde

2
+1 경쟁 조건의 결과가 크게 달라질 수 있습니다.
그랜트

+1 경쟁 조건의 결과는 해결되어야 할 주요 결정 요인이되어야합니다. 비행기 추락의 원인이 될 수있는 경쟁 조건은 사용자가 응용 프로그램을 다시 열도록하는 조건과는 다릅니다.
찌를

1
+1 : 그 결과는 아마도 당신이 분석해야 할 것이지, 그것이 일어날 확률은 아니라고 말할 것입니다. 결과가 중요하지 않은 경우 경쟁 조건이 매우 일반적인 경우에도 처리하지 않아도됩니다.
Leo

1
그러나 경쟁 조건을 자동으로 수정하면 더 많은 코드를 작성해야한다고 가정하지 마십시오. 큰 버그 덩어리를 제거하고 더 작은 코드 덩어리로 대체해야 할 수도 있습니다.
JesperE

45

경쟁 조건을 찾는 것은 어려운 일입니다. 이 문제를 해결하는 데 걸리는 시간과 거의 같은 시간을 보냈습니다. 쉽게 읽을 수 없게 만드는 것은 아닙니다. 프로그래머 는 그러한 상황에서 동기화 코드를 보게 될 것으로 예상 하고, 왜 존재하지 않는지 궁금해하고 추가하면 관련되지 않은 버그를 수정하는 데 더 많은 시간을 낭비 할 수 있습니다 .

확률에 관한 한, 당신은 놀랄 것입니다. 나는 자동화 시도 수천 재현 할 수 있지만, 지난해 경쟁 조건 버그 리포트를 가지고 하나 의 시스템을 하나 명의 고객이 모든 시간을 보았다. 고객이 설치할 때 "불가능한"버그를 해결하는 것과 비교하여 지금 수정하는 데 5 분을 소비하는 비즈니스 가치는 선택의 여지가 없습니다.


1
이것도! 다른 프로그래머가 코드를 읽을 때 발생할 수있는 문제에 대해 숙고하지 마십시오 (필요하지 않은 경우에도).
Casey Kuball

"지금 수정하는 데 5 분"이 걸리지 않는다는 점을 제외하고는 귀하의 요점을 잘 알고 있습니다 (지금 만든 수정은 나중의 수정보다 빠르고 저렴합니다).
iconoclast

2
경쟁 조건의 확률이 아마의 가능성이 보인다 그렇게하더라도 여러 가지 요인에 달려 있다는 지적 +1 당신 은 고객의 시스템에 더 자주 발생할 수 있습니다, 구성 / 다른 OS에 / 다음 버전 등의
sleske

27

잠금을 획득하고 해제하십시오. 확률이 변경되고 알고리즘이 변경됩니다. 들어가는 것은 나쁜 습관이며, 무언가 잘못되었을 때 멈추지 않고 확률이 잘못되었는지 궁금 할 필요는 없습니다 ...


6
알고리즘 변경에 +1 지금은 경쟁 조건을 알고있을 때 확률이 낮습니다. 1 년 후 경쟁 조건을 잊어 버린 경우 버그의 타이밍과 확률을 크게 변경하는 코드를 변경할 수 있습니다.
Phil

13

다른 스레드가 네트워크를 통해 데이터를 폴링하거나 작업을 완료하는 데 5-10 초가 걸리는 것으로 확인되었습니다.

누군가 성능을 향상시키기 위해 캐싱 레이어를 도입 할 때까지. 갑자기 다른 트레드가 거의 즉각적으로 끝나고 경쟁 조건이 종종 더 자주 나타납니다.

정확히 몇 주 전에이 문제가 발생했다면 버그를 찾는 데 약 2 일이 걸렸습니다.

경쟁 조건을 인식하면 항상 수정하십시오.


8

단순 대 정확.

많은 경우 단순성은 정확성보다 우선합니다. 비용 문제입니다.

또한 경쟁 조건은 단순한 통계에 따르지 않는 불쾌한 일입니다. 관련이없는 것으로 보이는 다른 동기화로 인해 경쟁 조건이 갑자기 절반으로 줄어들 때까지 모든 것이 제대로 작동합니다. 물론 로그를 켜거나 코드를 디버깅하지 않는 한.

경쟁 조건을 방지하기위한 실용적인 대안은 까다로울 수 있습니다. 그것이 일어나지 않으면, 당신은 거의 잃지 않았습니다. 실제로 이런 일이 발생하면,이를 고치는 데 추가 시간을 할애 할 수있는 확실한 근거가 있습니다.


1
로그 수정에 +1 한 후이를 수정하는 것이 너무 복잡하면 조기에 실패합니다.
Martin Ba

많은 경우 단순성은 완전성을 능가합니다. 이러한 경우에는 동기화가 거의 이루어지지 않습니다. 나중에 항상 당신을 물기 위해 (또는 코드를 유지 관리하는 가난한 사람) 거의 다시 올 것입니다.
reirab

@reirab 동의하지 않습니다. 드문 이벤트를 고려하면 기록 된 실패가 비용 효과적입니다. 예 : 사용자가 정확한 월 전환 (1/31 23:59:00-> 2/1 00:00:00)으로 네트워크를 전환하는 경우 전화 앱에 1/100 실패율 (충돌)이있는 경우 아마 그것에 대해 듣지 못할 것입니다. 그러나 서버 연결시 1 / 10 ^ 9의 충돌 가능성은 허용되지 않습니다. 따라 다릅니다.
ptyx

7

경쟁 조건이 보안과 관련이있는 경우이를 방지하기 위해 항상 코딩해야합니다.

일반적인 예는 유닉스에서 파일을 만들거나 여는 경합 조건입니다. 경합 조건을 가진 프로그램이 사용자가 시스템 데몬 프로세스 또는 더 나쁜 것은 커널이다.

경쟁 조건에 10 ^ (-80)의 확률이 무작위로 발생 하더라도 결정된 공격자가 의도적으로 인공적으로 그러한 조건을 생성 할 수있는 적절한 기회가있을 수 있습니다.


6

테라 크 -25!

Therac-25 프로젝트의 개발자들은 치료 용 XRAY 머신에서 UI와 인터페이스 관련 문제 사이의 타이밍에 대해 매우 확신했습니다.

그들은해서는 안됩니다.

이 유명한 생명 사망 소프트웨어 재해에 대한 자세한 내용은 다음을 참조하십시오.

http://www.youtube.com/watch?v=izGSOsAGIVQ

또는

http://en.wikipedia.org/wiki/Therac-25

응용 프로그램은 의료 기기보다 고장에 덜 민감 할 수 있습니다. 유용한 방법은 생산 가능성이있는 제품과 제품 수명 기간 동안 발생할 수있는 비용으로 생산 될 수있는 모든 장치에 대해 위험 노출을 평가하는 것입니다.

마지막으로 코드를 작성하기로 선택했다면 (그리고 마치 들리는 것처럼 들리면) 시스템 내부 또는 외부의 컴퓨터가 빨라짐에 따라 몇 년마다 쉽게 0에서 벗어날 수있는 무어의 법칙을 고려해야합니다. 수천 장을 배송 할 경우 더 많은 영점을 적용하십시오. 사용자가이 작업을 수년간 매일 (또는 매월) 수행하는 경우 몇 가지를 더 멀리 가져 가십시오. Google Fiber를 사용할 수있는 곳에서 사용한다면 어떻게 되나요? UI 가비지가 GUI 작업 중반을 수집하면 경쟁에 영향을 줍니까? GUI 뒤에 오픈 소스 또는 Windows 라이브러리를 사용하고 있습니까? 업데이트가 타이밍에 영향을 줄 수 있습니까?

세마포어, 잠금, 뮤텍스, 배리어 동기화는 스레드 간의 활동을 동기화하는 방법 중 하나입니다. 잠재적으로 사용하지 않으면 프로그램을 유지 관리하는 다른 사람이 스레드 간의 관계에 대한 가정을 빠르게 전환하고 경쟁 조건에 대한 계산이 무효화 될 수 있습니다.

문제가 발생하는 것을 볼 수는 없지만 고객이 발생할 수 있으므로 명시 적으로 동기화하는 것이 좋습니다. 또한 경쟁 조건이 발생하지 않더라도 도요타가 몇 년 전에 프리우스와 관련되어 있었기 때문에 귀하 또는 귀하의 조직이 귀하의 코드를 보호하기 위해 법원에 소집 된 경우에는 어떻게됩니까? 방법론이 철저할수록 더 잘 지낼 수 있습니다. "우리는 코드가 실패 할 것임을 알고 있지만, 평생에는 일어나지 않을 것임을 보여주기 위해이 방정식을 작성했습니다." "

확률 계산은 다른 사람에게서 온 것 같습니다. 그들은 당신의 코드를 알고 있으며 오류가 발생하지 않았다는 것을 믿을만큼 충분히 알고 있습니까? 어떤 것에 대해 99.99997 %의 신뢰성을 계산했다면, 나는 또한 대학 통계 수업으로 되돌아 가서 항상 100 %를 얻지 못했다는 것을 기억하고 내 자신의 개인 신뢰도 추정치에서 상당히 몇 퍼센트를 돌려받습니다.


1
Therac-25의 언급에 +1 여기에 많은 중요한 교훈이 있습니다.
스튜어트 마크

이것이 좋은 대답이라고 생각하지만, 경쟁 GUI를 제거하지 않으면 취미 GUI 프로젝트로 인해 사람들이 죽지 않을 것이라고 주장 할 수 있습니다.
marktani

나는 논쟁을 많이하지는 않지만, 내가 코드를 작성할 때마다 코드를 올바르게 작성해야한다고 주장 할 수 있습니다. 코드가 단순하고 아마도 유일한 저자 인 취미 프로젝트에서 경쟁 조건을 극복하는 것을 연습 할 수 있다면, 여러 저자의 작업을 통합해야하는 작업 프로젝트를 처리 할 때 훨씬 더 준비가 될 것입니다.
DeveloperDon

4

가독성을 방해하기 위해 더 많은 코드 줄을 추가하는 것이 완전히 불필요하거나 역효과를 낳을까요?

단순성은 또한 정확할 때만 좋습니다. 이 코드는 정확하지 않기 때문에 미래의 프로그래머 관련 버그를 찾을 때 필연적 으로이 코드를 볼 입니다.

어떻게 처리하든 (로그 기록, 문서화 또는 잠금 추가-비용에 따라 다름) 코드를 볼 때 다른 프로그래머의 시간을 절약 할 수 있습니다.


3

상황에 따라 다릅니다. 캐주얼 아이폰 게임이라면 아마 아닐 것입니다. 아마도 다음 유인 우주 차량을위한 비행 제어 시스템 일 것입니다. 그것은 '불량한'결과가 결과를 고치는 데 드는 예상 비용과 비교하여 발생하는 경우 결과가 무엇인지에 달려 있습니다.

프로그래밍 질문이 아니라 경제적 인 질문이기 때문에 이러한 유형의 질문에 대해 '하나의 크기에 모두 맞는'답변은 거의 없습니다 .


3
"다음 유인 우주 차량을위한 비행 제어 시스템" 확실히 .
deworde

아마 ... 확실히 ... 로켓에 누가 있었는지에 달려있을 것입니다 :-)
GrandmasterB

3

예, 예상치 못한 것을 기대하십시오. 나는 결코 일어나지 않아야 할 조건을 추적하는 데 몇 시간 (다른 사람들의 코드에서는 ^)을 보냈습니다.

항상 else가있는 경우, 항상 기본값이 있으며 변수를 초기화하고 (예, 실제로 버그가 발생합니다) 루프마다 반복마다 재사용되는 변수가 있는지 확인하십시오.

스레드 문제에 대해 특히 걱정이되는 경우 해당 주제에 대한 블로그, 기사 및 책을 읽으십시오. 현재 테마는 변경 불가능한 데이터 인 것 같습니다.


3

그냥 고쳐

나는 이것을 정확하게 보았다. 하나의 스레드는 복잡한 데이터베이스 조회를 수행하고 다른 스레드가 다음 코드 라인에 도달하기 전에 응답하는 서버에 네트워크 요청을 처리합니다. 일어난다.

어떤 고객은 언젠가는 느린 스레드를 실행하는 동안 "빠른"스레드에 대한 모든 CPU 시간을 낭비하는 것을 실행하기로 결정합니다. 죄송합니다 :)


1

가능성이 낮은 경쟁 조건을 인식했다면 최소한 코드에 기록하십시오!

편집 : 나는 가능한 경우 그것을 고쳐야한다고 덧붙여 야하지만, 위의 글을 작성할 때 다른 대답은 명시 적으로 코드의 문제를 문서화하지 않았다고 덧붙였습니다.


1
그래, 적어도 그것을 시도하고 감지하고 발생하면 기록하십시오. IMHO 모든 오류를 피하지 않는 것이 좋습니다. 그러나 적어도 누군가에게 그것이 일어났다는 사실과 그것이 잘못 인도되지 않았다는 가정을 알리십시오.
Steve Bennett

0

나는 그것이 어떻게 그리고 왜 일어날 수 있는지 이미 알고 있다면 그것을 처리 할 수 ​​있다고 생각합니다. 그것은 많은 양의 자원을 차지하지 않는 경우입니다.


0

그것은 모두 경쟁 조건의 결과에 달려 있습니다. 귀하의 질문에 답변하는 사람들은 자신의 업무 라인에 적합하다고 생각합니다. 광산은 라우터 구성 엔진입니다. 나를 위해 경쟁 조건은 시스템이 성공적이라고 말했지만 시스템이 여전히 정지 상태이거나 손상되었거나 구성되지 않은 상태로 만듭니다. 라우터마다 세마포어를 사용하므로 손으로 아무것도 정리할 필요가 없습니다.

내 GUI 코드 중 일부는 경쟁 조건이 발생하여 사용자에게 오류가 발생할 수있는 경쟁 조건으로 여전히 경향이 있다고 생각하지만 데이터 손상이나 오류가 발생할 가능성이있는 경우 그러한 가능성이 없습니다. 그런 사건 후에 신청하십시오.


0

재미있게도 최근 에이 문제가 발생했습니다. 나는 내 상황에서 경쟁 조건이 가능하다는 것을 깨닫지 못했습니다. 경쟁 조건은 멀티 코어 프로세서가 표준이되었을 때만 나타납니다.

시나리오는 대략 이와 같습니다. 장치 드라이버가 소프트웨어가 처리 할 이벤트를 발생 시켰습니다. 장치의 시간 초과를 방지하기 위해 제어 장치는 가능한 빨리 장치 드라이버로 돌아와야했습니다. 이를 보장하기 위해 이벤트가 별도의 스레드에 기록되고 큐에 대기되었습니다.

Receive event from device:
{
    Record event details.
    Enqueue event in the queuing thread.
    Acknowledge the event.
}

Queueing thread receives an event:
{
    Retrieve event details.
    Process event.
    Send next command to device.
}

이것은 수년간 잘 작동했습니다. 그런 다음 특정 구성에서 갑자기 실패합니다. 큐 스레드가 단일 프로세서의 시간을 공유하는 것이 아니라 실제로 이벤트 처리 스레드와 병렬로 실행되고 있음이 밝혀졌습니다. 이벤트가 확인되기 전에 장치에 다음 명령을 보내서 순서를 벗어난 오류가 발생했습니다.

하나의 구성에서 한 명의 고객에게만 영향을 주었으므로 Thread.Sleep(1000)문제가 발생한 위치를 부끄럽게 입력했습니다 . 이후 문제가 없었습니다.

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