2016-06-09 10 views
-1

하나의 전용 스레드에 의해 관리되는 데이터베이스 쓰기 작업 큐가 있습니다. 그리고 나는 원할 때마다 데이터베이스에서 읽는 많은 스레드를 가지고있다.ReaderWriterLockSlim LockRecursionPolicy.SupportsRecursion DeadLock

읽기/쓰기 액세스 제어에 ReaderWriterLockSlim을 사용하고 있습니다.

제 질문은 - 왜 LockRecursionPolicy.SupportsRecursion을 권장하지 않습니까? MSDN의 문서는 말한다 : 불필요한 합병증을 소개하고 교착 상태에 코드를 더욱 경향이 있습니다 때문에

재귀의 사용은, 새로운 개발하지 않는 것이 좋습니다.

여기서 교착 상태가 발생할 수 있습니까? 예를 들어, WriteReadLock을 이미 가져 왔을 때 (그리고 내가 SupportsRecursion 정책에 따라) EnterReadLock을 호출하려고하면 예외가 발생합니다 ...

답변

2

잠금 재귀는 원본을 그대로 두지 않고 동일한 스레드에서 동일한 잠금을 여러 번 취하는 것을 가리 킵니다 자물쇠.

이 문제의 주요 문제는 처음부터 그러한 상황에 처하게되면 필요한 동기화를 처리하는 사람과 관련하여 심각한 문제가있는 것입니다. 잠금이 너무 세분하거나 너무 광범위 할 수 있습니다. 멀티 스레딩은 어려우며 더 어렵게 만드는 것은 완전히 엉망입니다.

두 번째 큰 문제는 잠금이 스레드에 묶여 있다는 것입니다. 그러나 비동기 코드를 작성하는 경우 코드가 다른 스레드간에 점프 할 수 있습니다. 코드가 인 것처럼 보일 수 있습니다.은 재귀 잠금을 취하는 것입니다. 외부 잠금은 내부 잠금 장치와는 다른 스레드이며, 스레드 A가 스레드 B를 끝내기를 기다리면서 영원히 교착 상태에있는 반면, B는 A가 외부 잠금 장치를 해제 할 때까지 기다리고 있습니다.

재귀가 활성화되어 있어도 ReaderWriterLockSlim에서 많은 재귀 예외가 발생한다고 언급했습니다. 그리고 예, 이것은 재귀 적 잠금을 사용하는 것이 예를 들어를 다룰 때보 다 조금 더 안전하다는 것을 의미합니다. ReaderWriterLock 또는 Monitor. 규칙은 명확 MSDN에 설명되어 있습니다 : 재귀를 허용하는 ReaderWriterLockSlim의 경우

, 다음 스레드가 입력 할 수있는 모드에 대해 말할 수있다 :

  • 읽기 모드에서 스레드 모드를 반복적으로 읽을 입력 할 수 있습니다 쓰기 모드 또는 업그레이드 가능 모드로 전환 할 수 없습니다. 이 작업을 시도하면 LockRecursionException이 발생합니다. 읽기 모드로 들어가고 쓰기 모드 또는 업그레이드 가능 모드를 입력하는 것은 데드락 가능성이 높은 패턴이므로 허용되지 않습니다. 앞에서 설명했듯이 잠금을 업그레이드해야하는 경우 업그레이드 모드가 제공됩니다.
  • 업그레이드 가능 모드의 스레드는 쓰기 모드 및/또는 읽기 모드로 전환 할 수 있으며 세 가지 모드 중 하나를 재귀 적으로 시작할 수 있습니다. 그러나 읽기 모드에 다른 스레드가 있으면 쓰기 모드로 들어가려고 시도합니다.
  • 쓰기 모드의 스레드는 읽기 모드 및/또는 업그레이드 가능 모드에 들어가며 세 가지 모드 중 하나를 재귀 적으로 입력 할 수 있습니다.
  • 잠금에 들어 가지 않은 스레드는 어떤 모드로든 들어갈 수 있습니다. 이 시도는 비회원 잠금을 입력하려는 시도와 동일한 이유로 차단할 수 있습니다.

스레드는 해당 모드로 들어가는 횟수만큼 정확하게 각 모드를 종료 할 수있는 한 임의의 순서로 입력 된 모드를 종료 할 수 있습니다. thread가 모드를 종료 해, 모드를 종료하려고하면 (자), SynchronizationLockException가 Throw됩니다.

그들은 교착 상태를 일으키는 것으로 보장되는 재귀를 완전히 허용하지 않기 위해 최선을 다했습니다. 그렇다고해서 교착 상태가 발생하지 않는다는 의미는 아닙니다. 교착 상태를 일으키기 위해 재귀가 필요하지 않습니다. 교착 상태의 기회를 찾기가 어렵습니다. 물론 잠금에서 반복적으로 반복되는 코드에서 일관성 보장을 수행하는 것은 매우 어렵습니다. 즉, 외부 잠금에서 호출 될 때 일부 연산은 (반) 원자 적이지만 직접 호출되는 경우는 중단된다는 것을 의미 할 수 있습니다.

멀티 스레딩은 그대로 충분히 어렵습니다. 객체 디자인이 망가 졌기 때문에 더 어렵게 만들지 마라. 멀티 스레딩 (일반적으로 .NET에서 특히)에 대한 훌륭한 소개는 Joe Albahari의 "Threading in C#"이다. , Joe!). 특히 ReaderWriterLockSlimhttp://www.albahari.com/threading/part4.aspx#_Reader_Writer_Locks에서 처리됩니다.

+0

감사합니다. 그러나 SupportsRecursion 정책이 죽은 자물쇠에 훨씬 더 큰 위험을 초래하는 이유는 무엇입니까? 이 정책에 따라 다르게 수행 할 수있는 작업은 기본값 (NoRecursion)으로 수행 할 수 없습니다. –

+1

@PavelDurov 재귀 잠금의 일반적인 패턴은 모든 메서드와 속성이 공유 (인스턴스 별) 잠금을 사용하는 클래스와 비슷합니다. 일부 메소드는 다른 메소드를 호출하기 때문에 재귀 잠금이 필요합니다. 그러나 메소드 *의 일부분은 * lock 내부에서 실행되면 안됩니다. 예를 들어 이벤트를 발생시켜 사용자 코드를 호출하거나 다른 동기화 컨텍스트와 상호 작용할 수 있습니다. 어떤 종류의 재귀 적 잠금을 사용할 때 발생하는 것을 보장 할 방법이 없으며 교착 상태를 찾기가 매우 어렵습니다. – Luaan

+1

@PavelDurov 그 질문은 스택 오버 플로우에 대한 좋은 질문이 아닙니다. 프로그래머에게 물어볼 수도 있고, 편도 또는 다른 것을 논하는 사람들을 인터넷으로 둘러 볼 수도 있습니다 (일부 사람들은 여전히 ​​재귀 적 잠금 장치로 맹세하고, 일부는 확고히 반대합니다). 저의 관점에서 좋은 기사는 http://blog.stephencleary.com/2013/04/recursive-reententlocks.html입니다. – Luaan