2013-11-25 3 views
4

정적 멤버가있는 C# 클래스가 있는데,이 클래스는 여러 스레드에서 읽혀 하나의 스레드로 작성됩니다.C# 스레드 안전 정적 멤버

내가 아는 한 Uint64는 모든 시스템에서 원자 적 연산이 아니므로 스레드 안전성을 수동으로 보장해야합니다.

이 작업을 수행하는 방법에 대한 아이디어가 몇 가지 있습니다.

  1. C++에서 std :: atomic처럼 원자 랩퍼 클래스와 함께 사용하십시오. C#에서 구현 된 비슷한 것이 있습니까?

  2. 정적 필드와 함께 휘발성 수정 기호를 사용하십시오. 그러나 이것은 허용되지 않습니다. 왜?

    private static object tick_time_lock; 
    private static UInt64 _currentTickTime; 
    public static UInt64 CurrentTickTime 
    { 
        get 
        { 
         return _currentTickTime; 
        } 
        set 
        { 
         lock (tick_time_lock) 
         { 
          _currentTickTime = value; 
         } 
        } 
    } 
    

이이 필드를 스레드 안전하고 올바른 방법입니다

  • 는 드디어 다음나요?

  • +0

    그렇지만 스레드 설정이 많으면 속도가 느려집니다. 경쟁 조건도있을 것입니다. 예를 들어, 값을 ... 1로 업데이트하면 다음 스레드가이 값을 2로 업데이트 할 수 있지만 4 번째로 업데이트하면 ... 4와 3은 경쟁 조건으로 인해 나중에 들어올 수 있으며 마지막으로 최신 값. BTW, tick_time_lock 개체를 새로 작성해야합니다. –

    +0

    ['Interlocked] (http://msdn.microsoft.com/en-us/library/vstudio/system.threading.interlocked (v = vs.110) .aspx) 유틸리티 클래스를 찾고있을 수 있습니다. – millimoose

    답변

    5

    이이 분야는 스레드 안전하고 올바른 방법이 있나요?

    모두 주어진 리소스의 액세스가 동기화되지 않으면 모니터 잠금이 의미가 없습니다. get 접근자를 잠그지 않는 한 set 접근 자 주위에 자물쇠를다는 것은 아무 소용이 없습니다. 말하듯이 UInt64 값의 읽기 및 쓰기는 모든 플랫폼에서 원자 적이지 않습니다. 처음 단어가 set 접근 자에 기록 된 경우 필드가 get 접근 자에서 읽히면 어떻게됩니까? 찢어진 것을 읽게 될 것입니다.

    정적 필드와 함께 휘발성 수정 기호를 사용하십시오. 그러나 이것은 허용되지 않습니다. 왜?

    C# 언어 디자이너는 모든 volatile 필드 액세스가 원자적임을 보증하는 것이 유익하다고 생각했습니다. 절충 적으로 어떤 64 비트 필드도 volatile으로 선언 할 수 없습니다. 나는 왜 을 알지 못합니다. 이유는입니다. 어쩌면 그들은 휘발성 읽기/쓰기 작업에 "숨겨진"오버 헤드를 추가하는 것을 피하고 개발자가 64 비트 값을 처리하기 위해 Thread.Volatile[Read/Write](ref long)과 같은 프레임 워크 수준의 기능에 의존해야 할 수도 있습니다.

    C++에서 std :: atomic처럼 원자 래퍼 클래스와 함께 사용하십시오. C#에서 구현 된 비슷한 것이 있습니까?

    예. Read, Exchange, CompareExchange을 포함하여 System.Threading.Interlocked 클래스를 통해 노출되는 프레임 워크 수준의 원자 작업이 있습니다.

    1

    자물쇠 개체를 인스턴스화해야한다고 생각합니다. 또한 get에도 잠금 장치를 사용하십시오.

    private static Object tick_time_lock = new Object(); 
    private static UInt64 _currentTickTime; 
    public static UInt64 CurrentTickTime 
    { 
        get 
        { 
         lock (tick_time_lock) 
         { 
          return _currentTickTime; 
         } 
        } 
        set 
        { 
         lock (tick_time_lock) 
         { 
          _currentTickTime = value; 
         } 
        } 
    } 
    
    4

    Interlocked 클래스를 보면 여러 스레드가 공유하는 변수에 대해 원자 적 조작을 제공합니다.

    1

    아니, 당신은 완전히 잘못을하고 있습니다. 읽기/쓰기 작업 만 잠그면 도움이되지 않습니다. 예를 들어,이 코드는 스레드로부터 안전하지 않습니다하더라도 모두 얻을 세트가 잠금 장치에 의해 보호 될 수 있습니다

    var time = Clock.CurrentTickTime; 
    time += 1 
    Clock.CurrentTickTime = time 
    

    당신이 스레드 안전 있도록 모든 코드 주위에 잠 넣을 필요가있다.

    또한 시스템의 모든 구성 요소를 스레드로부터 보호하면 전체 시스템이 스레드로부터 안전함을 보장하지 않습니다. 실제로 교착 상태의 가능성을 높이고 디버깅을 어렵게 만듭니다.

    간단히 말해서 나사 각도가 완전히 틀린 방향으로 접근하고 있습니다. 먼저, 글로벌 상태를 동기화하는 것을 잊어 버리십시오. 전역 상태와 스레드 안전성을 모두 갖는 것은 매우 어렵습니다. 대신 모든 상태를 스레드 로컬로 유지하고 스레드 안전성을 보장 할 수있는 정확하게 정의 된 지점에서만이 상태를 동기화하십시오.