your programing

++ 연산자 스레드가 안전합니까?

lovepro 2020. 12. 29. 08:05
반응형

++ 연산자 스레드가 안전합니까?


이 질문에 이미 답변이 있습니다.

참고 : 저는 멀티 스레드 프로그래밍에 능숙하지 않지만 현재 프로젝트에서 제가 수행하고 있으므로 스레드로부터 안전한 것과 그렇지 않은 것에 대해 머리를 돌리려고합니다.

나는 ++ i 가하는 일에 대한 Eric Lippert의 멋진 답변 중 하나를 읽고있었습니다 . 그는 이것이 실제로 일어나는 일이라고 말합니다.

  1. x는 변수를 생성하기 위해 평가됩니다.
  2. 변수 값이 임시 위치에 복사됩니다.
  3. 임시 값이 증가하여 새 값을 생성합니다 (임시 값을 덮어 쓰지 않습니다!).
  4. 새 값은 변수에 저장됩니다.
  5. 작업의 결과는 새로운 값입니다.

이것은 내가 ++ i를 호출하는 두 개의 스레드가 있다면 어떨까요? 두 번째 스레드가 2 단계에있을 때 첫 번째 스레드가 3 단계에있는 경우 (첫 번째 스레드가 새 값을 변수에 저장하기 전에 두 번째 스레드가 값을 임시 위치로 복사하면 어떻게됩니까?)

그럴 경우 두 스레드가 i두 번이 아닌 한 번만 증가하는 것처럼 보입니다 . (전체 내용이 lock.)


다른 답변에서 지적했듯이 아니요, ++는 "스레드 세이프"가 아닙니다.

멀티 스레딩과 그 위험에 대해 배울 때 도움이 될 것이라고 생각하는 것은 "스레드 세이프"가 의미하는 바에 대해 매우 정확하게 시작하는 것입니다. 왜냐하면 다른 사람들은 다른 의미를 갖기 때문입니다. 본질적으로 여기서 염려하는 스레드 안전성 측면은 작업이 원자 적인지 여부 입니다. "원자 적"작업은 다른 스레드에 의해 중단 될 때 반쯤 완료되지 않도록 보장되는 작업입니다.

(원자 성과 관련이 없지만 여전히 일부 사람들의 스레드 안전성 정의에 속할 수있는 다른 스레딩 문제가 많이 있습니다. 예를 들어, 각각 변수를 변경하는 두 개의 스레드와 변수를 읽는 두 개의 스레드가 주어지면 두 개의 스레드가 있습니다. 독자 들은 다른 두 스레드가 돌연변이를 만든 순서동의 할 것을 보증 합니까? 당신의 논리가 그것에 의존한다면, 모든 읽기와 쓰기가 원자 적이라 할지라도 처리하기 매우 어려운 스레드 안전 문제가 있습니다.)

C #에서는 사실상 원 자성이 보장되지 않습니다. 간단히:

  • 32 비트 정수 또는 부동 소수점 읽기
  • 참조 읽기
  • 32 비트 정수 또는 부동 소수점 쓰기
  • 참조 작성

원 자성이 보장됩니다 (정확한 세부 사항은 사양 참조).

특히 64 비트 정수 또는 부동 소수점을 읽고 쓰는 것은 원 자성이 보장 되지 않습니다 . 당신이 말하는 경우:

C.x = 0xDEADBEEF00000000;

하나의 스레드에서

C.x = 0x000000000BADF00D;

다른 스레드에서 세 번째 스레드에서 가능합니다.

Console.WriteLine(C.x);

논리적으로 변수가 해당 값을 보유하지 않더라도 0xDEADBEEF0BADF00D를 작성하십시오 . C # 언어는 두 개의 int에 하나씩 쓰는 것과 동등한 긴 쓰기 권한을 보유하며 실제로 일부 칩은 그런 방식으로 구현합니다. 첫 번째 쓰기 후 스레드 전환으로 인해 독자가 예상치 못한 것을 읽을 수 있습니다.

장단점은 무언가를 잠그지 않고 두 스레드간에 아무것도 공유하지 않는다는 것입니다. 잠금은 만족할 때만 느립니다. 경합 잠금으로 인해 성능 문제가있는 경우 경합 잠금 으로 이어지는 아키텍처 결함수정하십시오 . 잠금 장치가 경쟁하지 않고 여전히 너무 느리다면 위험한 낮은 잠금 기술을 고려해야합니다.

여기서 사용하는 일반적인 저 잠금 기술은 물론를 호출하는 것입니다 Threading.Interlocked.Increment. 이것은 원 자성을 보장하는 방식으로 정수를 증가시킵니다. (그러나 두 스레드가 서로 다른 시간에 두 개의 서로 다른 변수의 연동 증분을 수행하고 다른 스레드가 어떤 증분이 "처음"발생했는지 확인하려고 할 때 어떤 일이 발생하는지에 대해서는 여전히 보장하지 않습니다. C #은이를 보장하지 않습니다. 모든 스레드에서 일관된 단일 이벤트 순서를 볼 수 있습니다.)


아니, 그렇지 않습니다.

당신이 생각 해낸 분석은 매우 정확합니다. ++(및 --) 연산자는 적절한 잠금 의미 체계와 함께 사용되지 않으면 경쟁 조건에 취약합니다.

이것들은 제대로 이해하기 어렵지만 고맙게도 BCL은 다음과 같은 특정한 경우에 대해 준비된 솔루션을 가지고 있습니다.

Interlocked.Increment원자 적 증분 작업을 원하는 경우 사용해야 합니다. 또한 클래스에 Decrement정의 된 여러 유용한 원자 연산이 Interlocked있습니다.

원자 적 연산으로 지정된 변수를 증가시키고 결과를 저장합니다.


아니요, i++간결 해 보이지만 실제로는 약어 i = i + 1이며 그 형식에서는 'i'의 읽기 및 쓰기가 포함된다는 것을 더 쉽게 알 수 있습니다. 잠그지 않으면 단순히 스레드로부터 안전하지 않습니다.

2 개의 다른 인수는 다음과 같습니다.

  • `++ '는 스레드로부터 안전한 것으로 정의되지 않았습니다.
  • 존재 Interlocked.Increment (ref int x)

스레드 안전성은 드물고 비용이 많이 들며 사용 가능한 경우 명확하게 광고됩니다.

참조 URL : https://stackoverflow.com/questions/4628243/is-the-operator-thread-safe

반응형