2017-05-16 1 views
0

여러 스레드에서 다음 코드를 호출하려고합니다.lock 문을 사용하지 않고 코드를 스레드로 안전하게 작성

// x is a global/member and initialized to 0 
if (Interlocked.Increment(ref x) == 2) 
{ 
    // do something only once 
} 

이 스레드 안전하지 물론이다 : 런타임에 첫 번째 스레드가 x이 증가 된 후 중지하지만, 평가하기 전에, 다음 두 번째 스레드 단위 x 그래서 그 다음, 지금 if 문 2 경우 true입니다. 그런 다음 첫 번째 스레드로 돌아가서 if 문에서도 마찬가지입니다.

이 코드는 lock 문으로 둘러 쌀 수 있습니다.

lock 문을 사용하지 않고 스레드를 안전하게 만들 수있는 방법이 있습니까?

+2

Interlocked.Increment() 메소드의 반환 값을 다른 스레드가 변경할 수 없기 때문에 설명 된 시나리오가 발생하지 않습니다. – dymanoid

+0

나중에 * x에 다시 액세스하여 증가 값과 같다고 가정하면 코드가 * 안전하지 않을 수 있지만이 문제를 보여주는 코드는 여기에 표시되지 않았습니다. –

답변

2

는 스레드로부터 안전하지 않습니다 : x 다른 스레드에 의해 변경 될 수 있었다, 그래서 다음과 같은 사실이 될 것이라고 전적으로 가능하다 증분되었지만 평가 전에. 그런 다음 두 번째 스레드가 증가하고 x는 2를 알고 있으므로 if 문이 true입니다. 그런 다음 첫 번째 스레드로 돌아가고 또한 사실임을 알고 있습니다.

이것은 사실이 아닙니다.

Interlocked.Increment은 원자 조작으로 추가로 lock이 필요하지 않습니다. (그렇지 않으면 그게 무슨 뜻입니까?)

값이 증가하고 증가 된 값을 얻습니다. 이후에 다른 증분이 발생하더라도 여전히 증분 된 첫 번째 값이 있습니다. 그래서 if는 false로 평가할 것입니다.

코드는 스레드로부터 안전합니다.

0

나는 당신이 틀렸다고 생각합니다. Interlocked.Increment의 반환 값은 평가 후 x 값이 아니라 증가 이후의 값입니다. x는 후 실행시에 첫 번째 스레드가 중지 된 경우 때문에 물론이다

int x = 1; 
var y = Interlocked.Increment(ref x); 

if(x!=y) 
관련 문제