2008-10-23 6 views
29

나는 C# &을 사용하고 있습니다. OptionA와 OptionB의 차이점은 무엇입니까?잠금 (락커)과 잠금 (variable_which_I_am_using)의 차이

class MyClass 
{ 
    private object m_Locker = new object(); 
    private Dicionary<string, object> m_Hash = new Dictionary<string, object>(); 

    public void OptionA() 
    { 
     lock(m_Locker){ 
      // Do something with the dictionary 
     } 
    } 

    public void OptionB() 
    { 
     lock(m_Hash){ 
      // Do something with the dictionary 
     } 
    }  
} 

(이 웹 사이트에 연결되지 않은 것 때문에, HttpCache에 클래스를 사용하지, 다중 스레드 앱의 캐시를 만들기위한 primarly) 내가 스레딩에 손 대고 시작하고, 나는이 OptionA 구문을 참조 많은 예에서 온라인으로 볼 수 있지만 OptionB를 통해 수행되는 이유가 무엇인지 이해하지 못합니다.

답변

27

옵션 B는 보호 할 개체를 사용하여 중요한 섹션을 만듭니다. 어떤 경우에는, 이것은 의도를보다 명확하게 전달합니다. 일관되게 사용하면 보호 오브젝트에 대한 한 개의 중요한 섹션 만 한 번에 활성화됩니다.

lock (m_Hash) 
{ 
    // Across all threads, I can be in one and only one of these two blocks 
    // Do something with the dictionary 
} 
lock (m_Hash) 
{ 
    // Across all threads, I can be in one and only one of these two blocks 
    // Do something with the dictionary 
} 

옵션 A는 덜 제한적입니다. 2 차 개체를 사용하여 보호 할 개체의 중요 섹션을 만듭니다. 복수의 2 차 오브젝트가 사용되는 경우, 보호 오브젝트에 대해 한 번에 둘 이상의 중요 섹션을 가질 수 있습니다.

private object m_LockerA = new object(); 
private object m_LockerB = new object(); 

lock (m_LockerA) 
{ 
    // It's possible this block is active in one thread 
    // while the block below is active in another 
    // Do something with the dictionary 
} 
lock (m_LockerB) 
{ 
    // It's possible this block is active in one thread 
    // while the block above is active in another 
    // Do something with the dictionary 
} 

옵션 A는 보조 개체를 하나만 사용하는 경우 옵션 B와 같습니다. 코드를 읽는 한, 옵션 B의 의도는 분명합니다. 두 개 이상의 객체를 보호하는 경우 옵션 B는 실제로 옵션이 아닙니다.

3

"잠금"은 잠금 장치가 아니므로 중요한 잠금 장치와 실행되지 못하게하는 코드 사이에 포함 된 코드입니다.

한 스레드가 임의의 객체에서 lock()을 꺼내면 다른 스레드가 동일한 객체에서 잠금을 얻지 못하도록하므로 두 번째 스레드가 중괄호 사이에서 코드를 실행하지 못하게합니다.

그래서 대부분의 사람들은 잠그기 위해 정크 개체를 생성하기 때문에 다른 스레드가 동일한 정크 개체에서 잠금을 얻지 못합니다.

+1

두 번째 및 세 번째 단락이 첫 번째 단락을 따르는 방식은 보이지 않습니다.이 단락은 잠금 기능이 중요하지 않다고 주장합니다. –

1

자물쇠에 의존합니다.

보통 m_Hash에만 스레드 접근 가능 액세스를 제공하기 위해 OptionB를 선택합니다. OptionA로는 잠금을 사용할 수없는 값 유형을 잠그는 데 사용했거나 동시에 잠금을 필요로하는 개체 그룹이 있었지만 사용하여 전체 인스턴스를 잠그지 않는 것이 무엇입니까? lock(this)

0

사용중인 개체를 잠그는 것은 간단합니다. 외부 잠금 객체 일 수 있으며 컬렉션과 마찬가지로 공유 리소스가 비공개 인 경우 필요합니다 (이 경우 ICollection.SyncRoot 객체 사용).

10

lock (m_Hash)은 이 아니고은 해시를 사용하지 못하도록합니다. m_Hash를 잠금 객체로 사용하는 다른 코드는 실행되지 않습니다.

옵션 A를 사용하는 한 가지 이유는 클래스에 lock 문 내에서 사용할 개인 변수가있을 가능성이 높기 때문입니다. 미세한 그레인 잠금을 사용하여 필요한 구성원 만 액세스 할 수있게하는 대신 모든 개체에 대한 액세스를 잠그는 데 사용하는 개체 하나를 사용하는 것이 훨씬 쉽습니다. 더 세분화 된 메소드를 사용하려고하면 어떤 경우에는 여러 개의 잠금을 취해야하며 교착 상태를 피하기 위해 항상 동일한 순서로 가져와야합니다.

옵션 A를 사용하는 또 다른 이유는 m_Hash에 대한 참조를 클래스 외부에서 액세스 할 수 있기 때문입니다. 아마도 당신은 그것에 대한 액세스를 제공하는 public 속성을 가졌을 것입니다. 그렇지 않으면 protected로 선언하고 파생 클래스가 사용할 수 있습니다. 어느 경우이든 외부 코드에 대한 참조가 있으면 외부 코드가이를 사용하여 잠금을 설정할 수 있습니다. 또한 잠금을 수행 할 순서를 제어하거나 알 수있는 방법이 없으므로 교착 상태가 발생할 수 있습니다.

2

"전달하는"변수의 범위가 잠금 범위를 결정한다고 생각합니다. 즉, 인스턴스 변수는 클래스 인스턴스와 관련되지만 정적 변수는 전체 AppDomain에 대한 것입니다.

(Reflector를 사용하여) 컬렉션의 구현을 살펴보면 패턴은 SyncRoot라는 인스턴스 변수가 선언되고 컬렉션의 인스턴스와 관련된 모든 잠금 작업에 사용되는 것처럼 보입니다.

7

실제로 멤버를 사용하는 경우 개체를 잠그는 것은 좋지 않습니다. 제프리 리히터 (Jeffrey Richter)는 자신의 저서 "CLR via C#"에서 동기화를 위해 사용하는 객체 클래스가 구현시 lock(this)을 사용하지 않을 것이라는 보장은 없다고 말했습니다. 흥미 롭지 만 Microsoft의 동기화를위한 권장 방법이었습니다. 얼마 동안은 ... 그런데 실수 였음을 알았습니다.) 그래서 항상 동기화를 위해 특별한 별도의 객체를 사용하는 것이 좋습니다. 그래서, 당신이 볼 수 있듯이 OptionB는 당신에게 데드락 안전성을 보장하지 않습니다. 따라서 OptionB가 OptionB보다 훨씬 안전합니다.

+0

"this"이외의 다른 객체를 사용하는 두 가지 방법을 다루는 질문에 실제로 대답하지 않습니다. –

+0

내 답변이 분명하지 않을 수 있습니다, 나는 그것을 조금 편집했습니다. –

0

OptionA는 모든 코드에서 m_hash에 액세스 할 때 m_Locker를 사용하여 잠금을 설정하면됩니다.

이제이 사례를 상상해보십시오. 당신은 물체를 잠근다. 호출 한 함수 중 하나의 객체에는 lock(this) 코드 세그먼트가 있습니다. 이 경우 확실한 복구 불가능한 교착 상태입니다

관련 문제