두 개의 스레드 우리가 IL 아래
class Counter
{
private static int s_Number = 0;
public static int GetNextNumber()
{
s_Number++;
return s_Number;
}
}
여기에 클래스 메소드에 대해 생성 IL code
보는 경우 동시에 GetNextNumber
방법에 액세스하려고 할 때 같은 수를 얻을 수 있습니다 이유를 쉽게 알 수있다 코드가 생성되고, 알다시피, s_number++
은 실제로 두 스레드가 동시에 액세스하여 동일한 초기 값을 얻을 수있는 세 개의 개별 명령어로 구성됩니다.
Counter.GetNextNumber:
IL_0000: ldsfld UserQuery+Counter.s_Number
IL_0005: ldc.i4.1
IL_0006: add
IL_0007: stsfld UserQuery+Counter.s_Number
IL_000C: ldsfld UserQuery+Counter.s_Number
IL_0011: ret
는
이는이 시점에서, 값 1로드되지만 두 스레드
thread A
가 들어가고 s_Number (IL_0000)의 값을 취득
동일한 값에 이르게 시나리오 프로세서는 thread A
을 일시 중단하고 thread B
을 시작합니다. 물론 s_number
에 정의 된 메모리 위치에 저장된 값은 여전히 0이고 스레드 B는 스레드 A와 동일한 값으로 시작합니다. 스레드는 다시 1이됩니다. 스레드 A가 다시 시작되면 레지스터는 일시 중지 시간에 복원되고, 그래서 0에 1을 가산 스레드 B. 동일한 결과를 다시 얻을
이 클래스는 동시성
class CounterLocked
{
private static object o;
private static int s_Number = 0;
public static int GetNextNumber()
{
lock(o)
{
s_Number++;
return s_Number;
}
}
}
CounterLocked.GetNextNumber:
IL_0000: ldc.i4.0
IL_0001: stloc.0 // <>s__LockTaken0
IL_0002: ldsfld UserQuery+CounterLocked.o
IL_0007: dup
IL_0008: stloc.2 // CS$2$0001
IL_0009: ldloca.s 00 // <>s__LockTaken0
IL_000B: call System.Threading.Monitor.Enter
IL_0010: ldsfld UserQuery+CounterLocked.s_Number
IL_0015: ldc.i4.1
IL_0016: add
IL_0017: stsfld UserQuery+CounterLocked.s_Number
IL_001C: ldsfld UserQuery+CounterLocked.s_Number
IL_0021: stloc.1 // CS$1$0000
IL_0022: leave.s IL_002E
IL_0024: ldloc.0 // <>s__LockTaken0
IL_0025: brfalse.s IL_002D
IL_0027: ldloc.2 // CS$2$0001
IL_0028: call System.Threading.Monitor.Exit
IL_002D: endfinally
IL_002E: ldloc.1 // CS$1$0000
IL_002F: ret
InterlockIncrement 위해 생성 된 코드는 매우 간단을 차단하는 로크 키워드를 사용
public static int GetNextNumber()
{
return Interlocked.Increment(ref s_Number);
}
CounterLocked.GetNextNumber:
IL_0000: ldsflda UserQuery+CounterLocked.s_Number
IL_0005: call System.Threading.Interlocked.Increment
IL_000A: ret
네, 그것은 가능성의 –
가능하지만이 가능하기 때문에이 상황을 처리해야합니다. 나는 lock 키워드를 사용할 것이다. – DGibbs
을 보장 할 수 없습니다하지만 그것은, 가능 –