2009-08-10 4 views
12

에서 스레드 안전 정적 변수를 만들어야합니다. 질문보다 조금 복잡합니다.C# .Net

class A 
{ 
    static int needsToBeThreadSafe = 0; 

    public static void M1() 
    { 
    needsToBeThreadSafe = RandomNumber(); 
    } 

    public static void M2() 
    { 
    print(needsToBeThreadSafe); 
    } 
} 

이제 M1()과 M2() 사이의 호출에서 'needsToBeThreadSafe'는 스레드 안전을 유지해야합니다.

+1

() 원자 수? – Bombe

+2

"스레드 안전"으로 무엇을 의미합니까? –

답변

18

는 무슨 질문을 시도 할 수있는 것은 [ThreadStatic] 속성입니다. 당신이 needsToBeThreadSafe 자체의 별도의 값을 가지도록 클래스를 A를 사용하는 각 스레드를 원한다면 당신은 단지 [ThreadStatic] 속성을 해당 필드를 장식해야합니다.

자세한 내용은 MSDN documentation for ThreadStaticAttribute을 참조하십시오.

static int needsToBeThreadSafe = 0; 
static System.Threading.ReaderWriterLockSlim rwl = new System.Threading.ReaderWriterLockSlim(); 

public static void M1() 
{ 
    try 
    { 
     rwl.EnterWriteLock(); 
     needsToBeThreadSafe = RandomNumber(); 
    } 
    finally 
    { 
     rwl.ExitWriteLock(); 
    } 

} 

public static void M2() 
{ 
    try 
    { 
     rwl.EnterReadLock(); 
     print(needsToBeThreadSafe); 
    } 
    finally 
    { 
     rwl.ExitReadLock(); 
    } 
} 
+0

다른 사람들도 모두 맞았지만 제 상황에서는 완벽하게 작동합니다. – Storm

+5

괜찮지 만 ThreadStatic은 ThreadSafe가 아닌 다른 것입니다. –

+0

어쨌든, 나는 그가 실제로 무엇을했는지는 쓰레드간에 공유되지 않는 값이라는 것을 깨달았습니다. 게다가 실제로 ThreadStatic **은 같은 변수를 액세스하는 스레드가 실제로는 없기 때문에 ** 스레드로부터 안전합니다. – paracycle

4
class A 
{ 
    static int needsToBeThreadSafe = 0; 
    static object statObjLocker = new object(); 

    public static void M1() 
    { 
     lock(statObjLocker) 
     { 
      needsToBeThreadSafe = RandomNumber(); 
     } 
    } 

    public static void M2() 
    { 
     lock(statObjLocker) 
     { 
      print(needsToBeThreadSafe); 
     } 
    } 
} 
+0

statObjLocker는 * readonly *이어야하며 예방 조치가 필요합니다. – ipavlu

8

두 가지 선택이있다 : 가장 쉬운 주어진 당신의 선물 코드가 volatile 키워드입니다. needsToBeThreadSafestatic volatile int으로 선언하면 해당 변수를 참조하는 모든 스레드가 "최신"복사본을 가져 오며 변수가 코드 내에 캐시되지 않음을 보장합니다.

더 일반적으로 M1()M2()이 "원자 적으로"(또는 적어도 독점적으로) 실행되도록하려는 경우 lock을 사용하려고합니다. 깨끗한 구문은 다음과 같은 "잠금 블록"함께 :

가지고있는 접근 방식, 즉 당신까지하고 코드에 의해 결정되어야한다으로
private static object locker = new Object(); 

//.. 

public static void M1() 
{ 
    lock(locker) 
    { 
     //..method body here 
    } 
} 

public static void M2() 
{ 
    lock(locker) 
    { 
     //..method body here 
    } 
} 

. 회원 할당이 모든 스레드에 전달되고 캐시되지 않는지 확인하는 것이 필요한 경우 volatile 키워드는 더 간단하며 올바르게 처리됩니다. 그 이상인 경우 lock과 함께 할 수 있습니다.

+0

사물함은 * 읽기 전용이어야하며 예방 조치 만해야합니다. – ipavlu

2

회원님의 소리는 Volatile입니다.

static volatile int needsToBeThreadSafe = 0; 
+0

2009 년 논평 이었지만 요즘에는 부작용이 있기 때문에 휘발성을 피하는 것이 가장 좋습니다 ... – ipavlu

2

당신은 또한 ReaderWriterLockSlim을 사용할 수 있습니다, 즉 더 효율적입니다.

class A 
{ 
    static volatile int needsToBeThreadSafe = 0; 

} 

을하지만 경우 :

그러나 더 미니멀 한 접근 방식이 존재는, 샘플 코드는 needsToBeThreadSafeint 원자이기 때문에 당신은 단지 휘발성 사용하여 컴파일러에 의해 캐싱을 방지 할 필요를 사용하여 하나의 문장을 보여줍니다 needToBeThreadSafe가 여러 문장에 걸쳐 'ThreadSafe'가되도록하려면 잠금을 사용하십시오. 정보

+0

rwl은 * readonly *, 그냥 예방책이어야합니다 ... – ipavlu

2

내가 답변 lock()를 사용하여 동의로, 즉 가장 안전한 방법입니다 시작하려면 : 복수의 읽기 및 덜 쓰기 위해

+0

2009 년 답변 이었지만 요즘에는 문제가 쉽게 발생하는 부작용이 있으므로 휘발성보다 휘발성보다 권장되는 잠금 장치를 사용하는 것이 좋습니다 ... – ipavlu

20

방법 : 당신은 M1()과 M2에 전화를 원하는 뜻

public static void M1() 
{ 
    Interlocked.Exchange(ref needsToBeThreadSafe, RandomNumber()); 
} 

public static void M2() 
{ 
    print(Interlocked.Read(ref needsToBeThreadSafe)); 
} 
+0

나는이 하나를 사랑하고, 안전하고 초고속입니다. SHAME는 5 년 만에 4 개의 upvotes (광산 포함)를 받았습니다! – ipavlu