programing tip

C #의 다양한 스레딩 동기화 옵션의 차이점은 무엇입니까?

itbloger 2020. 6. 4. 19:20
반응형

C #의 다양한 스레딩 동기화 옵션의 차이점은 무엇입니까?


누군가 다음의 차이점을 설명 할 수 있습니까?

  • 잠금 (someobject) {}
  • 뮤텍스 사용
  • 세마포어 사용하기
  • 모니터 사용
  • 다른 .Net 동기화 클래스 사용

난 그냥 알아낼 수 없습니다. 처음 두 사람이 같은 것 같습니다.


좋은 질문입니다. 어쩌면 틀렸을 수도 있습니다. 시도해 보도록하겠습니다. 약간의 이해를 가지고 오리지널 답변 2 번을 수정했습니다. 나를 읽어 주셔서 감사합니다 :)

잠금 (obj)

  • (intra-object?) 스레드 동기화를위한 CLR 구문입니다. 하나의 스레드 만 객체 잠금을 소유하고 잠금 된 코드 블록을 입력 할 수 있도록합니다. 다른 스레드는 현재 소유자가 코드 블록을 종료하여 잠금을 해제 할 때까지 기다려야합니다. 또한 클래스의 개인 멤버 객체를 잠그는 것이 좋습니다.

모니터

  • lock (obj)은 모니터를 사용하여 내부적으로 구현됩니다. 정리 절차를 잊어 버리는 것처럼 방해하지 않도록 lock (obj)을 선호해야합니다. 당신이 원한다면 그것은 모니터 구성을 '바보 방지'합니다.
    모니터는 .NET Framework 전용으로 설계되었으므로 리소스를 더 잘 사용하기 때문에 일반적으로 뮤텍스보다 모니터를 사용하는 것이 좋습니다.

잠금 또는 모니터를 사용하면 스레드에 민감한 코드 블록의 동시 실행을 방지하는 데 유용하지만 이러한 구성을 통해 한 스레드가 다른 이벤트와 통신 할 수는 없습니다. 이를 위해서는 스레드를 활성화하고 일시 중단하는 데 사용할 수있는 신호 및 신호 없음 상태 중 하나의 객체 인 동기화 이벤트가 필요 합니다. Mutex, Semaphores는 OS 수준의 개념입니다. 예를 들어 명명 된 mutex를 사용하면 여러 (관리되는) exe간에 동기화 할 수 있습니다 (시스템에서 한 응용 프로그램 인스턴스 만 실행되도록 보장).

뮤텍스 :

  • 그러나 모니터와 달리 뮤텍스를 사용하여 프로세스 간 스레드를 동기화 할 수 있습니다. 프로세스 간 동기화에 사용되는 뮤텍스는 다른 응용 프로그램에서 사용되기 때문에 명명 된 뮤텍스 라고 하므로 전역 또는 정적 변수를 통해 공유 할 수 없습니다. 두 애플리케이션 모두 동일한 뮤텍스 객체에 액세스 할 수 있도록 이름을 지정해야합니다. 반대로 Mutex 클래스는 Win32 구문의 래퍼입니다. 모니터보다 강력하지만 뮤텍스에는 Monitor 클래스에 필요한 것보다 계산 비용이 더 높은 interop 전환이 필요합니다.

세마포어 (뇌가 아프다).

  • Semaphore 클래스를 사용하여 자원 풀에 대한 액세스를 제어하십시오. 스레드는 WaitHandle 클래스에서 상속 된 WaitOne 메소드를 호출하여 세마포어에 들어가고 Release 메소드를 호출하여 세마포어를 해제합니다. 스레드가 세마포어에 들어갈 때마다 세마포어의 개수가 감소하고 스레드가 세마포어를 놓을 때 증가합니다. 개수가 0이면 다른 스레드가 세마포어를 해제 할 때까지 후속 요청이 차단됩니다. 모든 스레드가 세마포어를 해제하면 카운트는 세마포어가 작성 될 때 지정된 최대 값에 있습니다. 스레드는 세마포어를 여러 번 입력 할 수 있습니다. Semaphore 클래스는 WaitOne 또는 Release .. 프로그래머가 스레드를 해제하지 않도록 스레드 ID를 강요하지 않습니다. 세마포어는 로컬 세마포어와 이름이 있습니다.시스템 세마포어. 이름을 허용하는 생성자를 사용하여 Semaphore 오브젝트를 작성하면 해당 이름의 운영 체제 세마포어와 연관됩니다. 명명 된 시스템 세마포어는 운영 체제 전체에서 볼 수 있으며 프로세스 활동을 동기화하는 데 사용할 수 있습니다. 로컬 세마포어는 프로세스 내에서만 존재합니다. 로컬 세마포어 객체에 대한 참조가있는 프로세스의 모든 스레드에서 사용할 수 있습니다. 각 세마포어 객체는 별도의 로컬 세마포어입니다.

읽을 페이지-스레드 동기화 (C #)


"다른 .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 (시도 / 마지막 내에 존재)에 대한 컴파일러 마술입니다.

Monitors have a simple but powerful signal/wait mechanism that Mutexes don't have via the Monitor.Pulse/Monitor.Wait methods. The Win32 equivalent would be event objects via CreateEvent which actually also exist in .NET as WaitHandles. The Pulse/Wait model is similar to Unix's pthread_signal and pthread_wait but are faster because they can be entirely user-mode operations in the un-contended case.

Monitor.Pulse/Wait is simple to use. In one thread, we lock an object, check a flag/state/property and if it's not what we are expecting, call Monitor.Wait which will release the lock and wait until a pulse is sent. When the wait returns, we loop back and check the flag/state/property again. In the other thread, we lock the object whenever we change the flag/state/property and then call PulseAll to wake up any listening threads.

Often we want our classes to be thread safe so we put locks in our code. However, it is often the case that our class will only ever be used by one thread. This means the locks needlessly slow down our code...this is where clever optimisations in the CLR can help improve performance.

I'm not sure about Microsoft's implementation of locks but in DotGNU and Mono, a lock state flag is stored in the header of every object. Every object in .NET (and Java) can become a lock so every object needs to support this in their header. In the DotGNU implementation, there is a flag that allows you to use a global hashtable for every object that is used as a lock -- this has the benefit of eliminating a 4 byte overhead for every object. This is not great for memory (especially for embedded systems that aren't heavily threaded) but has a hit on performance.

Both Mono and DotGNU effectively use mutexes to perform locking/waiting but use a spinlock style compare-and-exchange operations to eliminate the need to actually perform a hard locks unless really necessary:

You can see an example of how monitors can be implemented here:

http://cvs.savannah.gnu.org/viewvc/dotgnu-pnet/pnet/engine/lib_monitor.c?revision=1.7&view=markup


An additional caveat for locking on any shared Mutex you've identified with a string ID is that it will default to a "Local\" mutex and will not be shared across sessions in a terminal server environment.

Prefix your string identifier with "Global\" to ensure that access to shared system resources is properly controlled. I was just running into a whole heap of problems synchronizing communications with a service running under the SYSTEM account before I realized this.


I would try to avoid "lock()", "Mutex" and "Monitor" if you can...

Check out the new namespace System.Collections.Concurrent in .NET 4
It has some nice thread-safe collection classes

http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx

ConcurrentDictionary rocks! no manual locking anymore for me!

참고URL : https://stackoverflow.com/questions/301160/what-are-the-differences-between-various-threading-synchronization-options-in-c

반응형