답변:
좋은 질문입니다. 어쩌면 내가 틀렸을 수도있다 나를 읽어 주셔서 감사합니다 :)
잠금 (obj)
모니터
잠금 또는 모니터를 사용하면 스레드에 민감한 코드 블록의 동시 실행을 방지하는 데 유용하지만 이러한 구성을 통해 한 스레드가 다른 이벤트와 통신 할 수는 없습니다. 이를 위해서는 스레드를 활성화하고 일시 중단하는 데 사용할 수있는 신호 및 신호 없음 상태 중 하나의 객체 인 동기화 이벤트가 필요 합니다. Mutex, Semaphores는 OS 수준의 개념입니다. 예를 들어 명명 된 mutex를 사용하면 여러 (관리되는) exe간에 동기화 할 수 있습니다 (시스템에서 하나의 응용 프로그램 인스턴스 만 실행되도록 보장).
뮤텍스 :
세마포어 (뇌가 아프다).
Monitor
의사 소통을 허용하지 않는다고 주장합니다 . 할 수 있습니다 여전히 Pulse
등등에Monitor
"다른 .Net 동기화 클래스 사용"을 다시 참조하십시오.
CCR / TPL ( Parallel Extensions CTP) 에는 더 많은 (오버 헤드가 적은) 잠금 구성이 있지만 IIRC는 .NET 4.0에서 사용할 수 있습니다.
ECMA에 명시된 바와 같이 Reflected 메소드에서 볼 수 있듯이 lock 문은 기본적으로
object obj = x;
System.Threading.Monitor.Enter(obj);
try {
…
}
finally {
System.Threading.Monitor.Exit(obj);
}
앞에서 언급 한 예에서 모니터가 객체를 잠글 수 있음을 알 수 있습니다.
Mutexe 는 문자열 식별자를 잠글 수 있으므로 프로세스 간 동기화가 필요할 때 유용합니다 . 다른 프로세스에서 동일한 문자열 식별자를 사용하여 잠금을 획득 할 수 있습니다.
세마포어는 스테로이드의 뮤텍스와 유사하며 최대 동시 액세스 수를 제공하여 동시 액세스를 허용합니다. 한도에 도달하면 호출자 중 하나가 세마포어를 해제 할 때까지 세마포어가 리소스에 대한 추가 액세스를 차단하기 시작합니다.
DotGNU에서 스레딩에 대한 클래스 및 CLR 지원을했는데 몇 가지 생각이 있습니다 ...
교차 프로세스 잠금이 필요하지 않으면 항상 Mutex & Semaphores를 사용하지 않아야합니다. .NET의 이러한 클래스는 Win32 Mutex 및 Semaphores를 감싸는 래퍼이며 다소 무겁습니다 (커널에 컨텍스트 전환이 필요하므로 비용이 많이 듭니다. 특히 잠금이 경합이 아닌 경우).
다른 사람들이 언급했듯이 C # lock 문은 Monitor.Enter 및 Monitor.Exit (시도 / 최종 내에 존재)에 대한 컴파일러 마술입니다.
모니터에는 Mutex가 Monitor.Pulse / Monitor.Wait 메소드를 통해 가지고 있지 않은 단순하지만 강력한 신호 / 대기 메커니즘이 있습니다. Win32에 해당하는 것은 CreateEvent를 통한 이벤트 객체이며 실제로 .NET에는 WaitHandles로도 존재합니다. Pulse / Wait 모델은 Unix의 pthread_signal 및 pthread_wait와 유사하지만 경쟁이없는 경우 완전히 사용자 모드 작업이 될 수 있으므로 더 빠릅니다.
Monitor.Pulse / Wait는 사용이 간편합니다. 하나의 스레드에서 객체를 잠그고 플래그 / 상태 / 속성을 확인하고 예상 한 것이 아닌 경우 Monitor.Wait를 호출하여 잠금을 해제하고 펄스가 전송 될 때까지 기다립니다. 대기가 돌아 오면 루프백하고 플래그 / 상태 / 속성을 다시 확인합니다. 다른 스레드에서는 플래그 / 상태 / 속성을 변경할 때마다 객체를 잠근 다음 PulseAll을 호출하여 수신 스레드를 깨 웁니다.
종종 우리는 클래스가 스레드로부터 안전하기를 원하므로 코드에 잠금을 설정합니다. 그러나 종종 클래스가 하나의 스레드에서만 사용되는 경우가 종종 있습니다. 이는 잠금이 코드를 불필요하게 느리게하는 것을 의미합니다. 이것은 CLR의 영리한 최적화가 성능 향상에 도움이되는 곳입니다.
Microsoft의 잠금 구현은 확실하지 않지만 DotGNU 및 Mono에서는 잠금 상태 플래그가 모든 개체의 헤더에 저장됩니다. .NET (및 Java)의 모든 객체는 잠금이 될 수 있으므로 모든 객체는 헤더에서이를 지원해야합니다. DotGNU 구현에는 잠금으로 사용되는 모든 객체에 대해 전역 해시 테이블을 사용할 수있는 플래그가 있습니다. 이는 모든 객체에 대해 4 바이트 오버 헤드를 제거 할 수 있다는 이점이 있습니다. 이것은 메모리 (특히 스레드가 많지 않은 임베디드 시스템)에는 좋지 않지만 성능에 영향을 미칩니다.
Mono와 DotGNU는 효과적으로 뮤텍스를 사용하여 잠금 / 대기를 수행하지만 스핀 록 스타일 비교 및 교환 작업을 사용하여 실제로 필요한 경우가 아니라면 실제로 하드 잠금을 수행 할 필요가 없습니다.
여기에서 모니터를 구현하는 방법의 예를 볼 수 있습니다.
http://cvs.savannah.gnu.org/viewvc/dotgnu-pnet/pnet/engine/lib_monitor.c?revision=1.7&view=markup
가능한 경우 "lock ()", "Mutex"및 "Monitor"를 피하려고합니다.
.NET 4의 새로운 네임 스페이스 System.Collections.Concurrent을 확인
그것은 멋진 스레드 안전 컬렉션 클래스를 가지고
http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx
동시 사전! 더 이상 수동 잠금 기능이 없습니다!
대부분의 경우 잠금 (= 모니터) 또는 뮤텍스 / 세마포어를 사용 하지 않아야 합니다. 그들은 모두 현재 스레드를 차단합니다.
그리고 클래스를 사용해서는 안됩니다. System.Collections.Concurrent
클래스는 여러 컬렉션 간의 트랜잭션을 지원하지 않고 현재 스레드를 차단하기 때문에 경쟁 조건의 주요 원인입니다.
놀랍게도 .NET에는 효과적인 동기화 메커니즘이 없습니다.
테스트를 통해 스레드 풀을 사용하는 동기화 도구를 차단하지 않고 매우 가벼운 C # 에서 GCD ( 세계)의 직렬 대기열 을 구현했습니다 Objc/Swift
.
데이터베이스 액세스 (hello sqlite)에서 비즈니스 로직에 이르기까지 대부분의 경우 동기화하는 가장 좋은 방법입니다.