2014-11-23 1 views
3

"_ht"는 캐시를 나타내는 Hashtable이고 "_isLoaded"는로드 된 코드를 나타냅니다.잠금 개체로 Hashtable을 사용할 수 있습니까?

Google 시스템에는 '_ht'개체에 액세스하는 많은 프로세스가 있으며로드되지 않은 경우 대기해야합니다.

"_ht"를 잠금 개체로 사용하는 것이 잘못 되었습니까? 이 시나리오에서 전용 객체 유형 클래스 멤버를 사용해야합니까?

이 클래스는 SINGLETON입니다.

private Hashtable _ht = new Hashtable(); 
private bool _isLoaded = false; 

internal Hashtable GetHT() 
     { 
      if (_isLoaded == false) 
      { 
       lock (_ht) 
       { 
        if (_isLoaded == false) 
        { 
         LoadHt(_ht); 
        } 
       } 
      } 

      return _ht; 
     } 
+0

잠금 개체를 사용하는 이유에 관해서는 내 대답을 사용하기를 원한다면, 꽤 분명하다고 생각합니다. 그렇지 않다면 생각해야합니다. 어쨌든 너는 –

+0

@ohadinho를 알고있다. 왜냐하면 _usually_ 별도의'object'가 사용되지만 당신이 잠그고있는 객체가'Hashtable'을 직접 사용하는 것은 잘못된 것보다'private' 일 때까지입니다. 클래스와 그 밖에 아무도 그 객체에 대해 잠글 수있는 객체의 가시성을 갖지 않으므로 죽은 자물쇠의 소스가 아닙니다. 그 말은 **이 코드 **를 모두 삭제하고'Lazy '을 사용하는 것입니다. –

+0

@AdrianoRepetti : _field_가 'private'로 선언 되었기 때문에 개체 자체가 비공개임을 의미하지는 않습니다. 그리고 실제로,이 예제에서'Hashtable' 객체는'GetHT()'메소드를 통해 ('internal'이지만 내부 클래스이지만 여전히) 공개됩니다. –

답변

10

을 지적 @PeterDuniho. 그러나 일반적으로 하나의 잠금 객체가 코드의 다른 부분에서 사용할 수있을 때 코드가 잠금을 사용하는 방식을 추적하는 것이 어렵 기 때문에 열등한 접근 방식으로 간주됩니다 (잠금을 위해 잠금 객체를 사용할 수도 있습니다). 다시 말하지만, 사람들이 때때로 쓰는 코드에 놀랄 것입니다.)

일반적으로 잠금의 경우 별도의 잠금 개체가 바람직합니다. 코드 예에서 _htreadonly이어야하며 별도의 잠금 객체 (예 : lockObj)를 추가하면 읽기 전용이어야합니다.

그렇다고 싱글 톤 시나리오를 이런 방식으로 구현하면 안됩니다.

private static readonly Hashtable _ht = InitializeTable(); 

internal static Hashtable GetHT() { return _ht; } 

private static Hashtable InitializeTable() 
{ 
    Hashtable table = new Hashtable(); 

    LoadHt(table); 

    return table; 
} 

또는 : 대신, 당신은 CLR 자신의 정적 초기화, 또는 Lazy<T> 클래스를 사용해야 하나

private static readonly Lazy<Hashtable> _ht = new Lazy<Hashtable>(() => InitializeTable()); 

internal static Hashtable GetHT() { return _ht.Value; } 

private static Hashtable InitializeTable() 
{ 
    Hashtable table = new Hashtable(); 

    LoadHt(table); 

    return table; 
} 

당신이 액세스 할 수있는 유형의 다른 구성원이있을 때 후자가 유용합니다, 하지만 가능한 한 오랫동안 해시 테이블 초기화가 지연되도록해야합니다 (예 : 실제로 코드에 액세스 할 수없는 경우이를 초기화하지 않아도 됨).

(나는 시나리오를 싱글 톤으로 설명했기 때문에 모든 것을 static으로 변경했으며이 경우 코드 예제에서는 static 구성원 만 이해할 수 있음).

마지막으로 Hashtable 클래스의 기한이 오래되었습니다. 비 제네릭 클래스로서, 당신은 정말로 코드를 10 년 된 제네릭 타입을 사용하도록 업그레이드하는 것을 진지하게 고려해야합니다. Dictionary<TKey, TValue> 클래스가 가장 직접적인 대체 클래스이지만 사람들은 간략한 집합으로 Hashtable을 사용하기 때문에 HashSet<T> 데이터 구조가 더 적절할 수 있습니다.

+0

대답을 제외하고는 "문자열을 제외하고 .NET에서 참조 유형 인스턴스를 사용할 수있는 것처럼"예외가됩니다. 문자열이 불변이므로 잠금 객체로 문자열을 효과적으로 사용할 수 없으므로 참조가 동일한 문자열 값을 가진 다른 모든 코드간에 공유됩니다. – PhillipH

+1

@ 필립 : 죄송합니다. 진술이 잘못되었습니다.첫째,'string'이 불변이라는 사실은 결코 같지 않은 모든'string'이 실제로 동일한 객체라는 것을 의미합니다 (기본적으로'string' 리터럴 만이 포함됩니다). 둘째, 그것이 의미한다고해도, 그것은 'lock' 문에서'string '참조를 사용하는 것을 배제하지 않습니다. 두 번이나 현명하지 않을 수도 있지만 확실히 가능합니다. –

+0

솔루션에 감사드립니다. 질문이 있습니다 : "GetHT()"및 Hashtable을 실행하려고하는 10 개의 스레드가로드되지 않은 경우. 오직 하나의 스레드가 실행됩니다. InitializeTable() 정체 적이기 때문에 ?? – ohadinho

2

여기에있는 첫 번째 스레드를 원한다면 시작하십시오. 괜찮습니다. 하지만 일반적으로 잠금 객체를 사용합니다.

private Hashtable _ht = new Hashtable(); 
private bool _isLoaded = false; 
private object lockObj = new object(); 

internal Hashtable GetHT() 
{ 
    if (_isLoaded == false) 
    { 
     lock (lockObj) 
     { 
      if (_isLoaded == false) 
      { 
       LoadHt(_ht); 
      } 
     } 
    } 

    return _ht; 
} 
+0

사람들이 잘못 구현하는 것보다 다른 이유로 (여기에있는 것처럼) 이중 확인 잠금은 일반적으로 피해야합니다. .NET은 적어도 두 가지 다른 우수한 구현 옵션을 제공하기 때문에 .NET에서는 불필요합니다. http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Microsoft_.NET_.28Visual_Basic.2C_C.23.29, http://stackoverflow.com/a/394932/3538012 및 http://csharpindepth.com/을 참조하십시오. 기사에 대한 추가 토론은 기사/일반/Singleton.aspx를 참조하십시오. –

+0

이것은 싱글 톤 패턴이 아니지만 이러한 종류의 이중 검사 잠금은 깨졌습니다. '_ht'가'LoadHt' 메쏘드 안에서 인스턴스화되면, 프로세서는'_ht'와'_isLoaded'를 재 배열하여'null'을 반환 할 수 있습니다. 참조 http://joeduffyblog.com/2006/01/26/broken-variants-on-doublechecked-locking/ –

+0

@SriramSakthivel : 사실 더피 (Duffy) 블로그 기사의 예보다 더 나 빠졌습니다. 이 예제에서,'_isLoaded' 변수는 결코 할당되지 않습니다. 그래서 Duffy가 말하고있는 문제를 우연히 발견 할 기회조차 얻지 못합니다. :) 그러나 예, 휘발성 읽기의 부족은 또한 여기의 문제입니다. 이것이 필자가 항상 자신의 이중 체크 잠금을 구현하려는 것에 대해 강하게 반대하는 이유이다. 상대적으로 소수의 프로그래머가 올바르게 사용하고 .NET에서 사용하기 쉬운 대안이 있습니다. –

1

개체 자체가 잠기기 (보호됨)로 시작하지 않습니다. lock 키워드에 사용 된 참조는 동일한 객체 참조를 사용하는 다른 (또는 동일한) 코드 섹션과 동시에 실행하면 안되는 코드 섹션을 표시하거나 태그하는 데 사용됩니다. 실제로 개체 자체에 영향을주지는 않습니다. 대답은 입니다. 기존 HashTable 인스턴스를 lock 문에 사용할 수 있습니다.

Best practice 그러나 잠글 사설 개체를 정의하거나 모든 인스턴스에 공통된 데이터를 보호하기 위해 개인 정적 개체 변수를 정의하는 것입니다.

private Object thisLock = new Object(); 

편집 덕분에 당신은 확실히 당신이 lock 성명에서 .NET의 모든 참조 형 인스턴스를 사용할 수있는 것처럼의 Hashtable 개체를 잠글 수 있습니다

+0

"새로운 개체"에 대한 진술을 고쳐 주셔서 감사합니다. 또한 "동일한 객체 참조를 사용하는 코드 섹션"을 명확하게 제안 할 것입니다. 여러분도 아시다시피, 'lock' 문에서 동일한 객체 참조를 사용하는 코드 섹션 만 보호합니다. 'lock' 문을 사용하지 않고 객체를 사용하는 코드는 비동기 상태로 남습니다. 나는 당신이 단순히 "... lock 문"에서 같은 객체 참조를 사용한다고 말하면서 오해를 막을 수 있다고 생각합니다. –

관련 문제