동기화 : 작업들 사이의 수행 시기를 맞추는 것
다수의 스레드가 동시에 공유 자원을 사용할 때 순서를 정하는 것
동기화 키워드
Lock
lock(C#) 사용하면 다른 스레드의 방해를 받지 않은 채 코드 블록의 실행을 완료할 수 있습니다.
이를 위해서는 코드 블록을 진행하는 동안 지정된 개체에 대한 상호 배타적 잠금을 유지해야 합니다.
lock 문은 개체를 인수로 지정하며 뒤에 한 번에 하나의 스레드에서만 실행할 코드 블록이 나옵니다.12345678910public class TestThreading {private System.Object lockThis = new System.Object();public void Process(){lock (lockThis) {// Access thread-sensitive resources.}}}cs Monitor
lock 및 SyncLock 키워드와 마찬가지로 monitor를 사용하면 코드 블록이 여러 스레드에서 동시에 실행되지 않도록 방지할 수 있습니다.
Enter 메서드를 사용하면 스레드 하나만 다음 문으로 진행하도록 허용할 수 있습니다.
다른 모든 스레드는 현재 실행 중인 스레드가 Exit를 호출할 때까지 차단됩니다.
lock 키워드를 사용할 때와 동일합니다.1234567System.Object obj = (System.Object)x;System.Threading.Monitor.Enter(obj);try {DoSomething();} finally {System.Threading.Monitor.Exit(obj);}cs Mutex
뮤텍스는 monitor와 비슷합니다.
이는 한 번에 여러 스레드에서 코드 블록이 동시에 실행되는 것을 방지합니다.
사실 "뮤텍스(mutex)"라는 용어는 "상호 배타적(mutually exclusive)"이라는 표현의 줄임말입니다.
그러나 monitor와 달리 뮤텍스를 사용하면 프로세스 간에 스레드를 동기화할 수 있습니다.
뮤텍스는 Mutex 클래스로 표현됩니다.
프로세스간 동기화에 사용되는 뮤텍스를 명명된 뮤텍스라고 합니다.
이는 다른 응용 프로그램에 사용하기 위한 것이며 전역 또는 정적 변수를 통해 공유할 수 없기 때문입니다.
두 응용 프로그램에서 모두 동일한 뮤텍스 개체에 액세스할 수 있도록 이 뮤텍스에 이름을 지정해야 합니다.
프로세스 내의 스레드를 동기화하는 데 뮤텍스를 사용할 수도 있지만 일반적으로 Monitor를 사용하는 것이 더 좋습니다.
monitor는 .NET Framework용으로 특별히 디자인되었으며 리소스를 더 효율적으로 활용하기 때문입니다.
반면, Mutex 클래스는 Win32 구문에 대한 래퍼입니다.
이는 monitor보다 더 강력하지만 뮤텍스를 사용하려면 Monitor 클래스에 필요한 것보다 더 처리가 복잡한 interop 전환이 필요합니다.12345678910111213141516171819202122232425262728using System;using System.Threading;namespace MainServer {class Program {static Mutex m_mutex = new Mutex();static int m_count;static void Main(string[] args){Thread thread1 = new Thread(new ThreadStart(ThreadProc));thread1.Start();Thread thread2 = new Thread(new ThreadStart(ThreadProc));thread2.Start();}static void ThreadProc(){m_mutex.WaitOne();for (int i = 0; i < 5; i++) {m_count++;Console.WriteLine($"Thread ID: {Thread.CurrentThread.GetHashCode()} {m_count}");}m_mutex.ReleaseMutex();}}}cs Interlocked
Interlocked의 메서드를 사용하면 여러 스레드에서 같은 값을 동시에 업데이트하거나 비교하려고 할 때 발생할 수 있는 문제를 방지할 수 있습니다.
이 클래스의 메서드를 사용하면 모든 스레드에서 값을 안전하게 늘리거나, 줄이거나, 교환하거나, 비교할 수 있습니다.AutoResetEvent
AutoResetEvent를 사용하면 스레드가 신호를 통해 서로 통신 할 수 있습니다.
일반적으로 스레드가 리소스에 독점적으로 액세스해야하는 경우이 클래스를 사용합니다ManualResetEvent
ManualResetEvent 스레드가 신호를 보내 서로 통신할 수 있습니다.
일반적으로이 통신 하나의 스레드가 다른 스레드에서 진행 되기 전에 완료 해야 하는 작업에 관여 합니다.ReaderWriterLock
일부 경우에는 데이터를 쓰고 있을 때만 리소스를 잠그고 데이터를 업데이트하지 않을 때는 여러 클라이언트에서 동시에 데이터를 읽을 수 있도록 할 수 있습니다.
ReaderWriterLock 클래스를 사용하면 스레드에서 리소스를 수정하는 동안은 리소스를 단독으로 사용하고 리소스를 읽을 때는 여러 스레드에서 동시에 사용하도록 할 수 있습니다.
ReaderWriter 잠금은 해당 스레드에서 데이터를 업데이트할 필요가 없는 경우에도 다른 스레드를 대기하도록 만드는 단독 잠금 대신 사용할 수 있는 유용한 기능입니다.
동기화 이벤트 및 대기 핸들(AutoResetEvent, ManualResetEvent)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | using System; using System.Threading; class ThreadingExample { static AutoResetEvent AutoEvent; static ManualResetEvent ManualEvent; static void DoWork1() { Console.WriteLine("DoWork1 작업자 스레드가 시작(AutoEvent 이벤트를 기다림)"); AutoEvent.WaitOne(); Console.WriteLine("DoWork1 작업자 스레드가 다시 활성화 됨"); for (int i = 0; i < 10; i++) { Console.WriteLine($"DoWork1 작업자 중... {i}"); } Console.WriteLine("DoWork1 작업자 스레드 종료"); } static void DoWork2() { Console.WriteLine("DoWork2 작업자 스레드가 시작(ManualEvent 이벤트를 기다림)"); ManualEvent.WaitOne(); Console.WriteLine("DoWork2 작업자 스레드가 다시 활성화 됨"); for (int i = 0; i < 10; i++) { Console.WriteLine($"DoWork2 작업자 중... {i}"); } Console.WriteLine("DoWork2 작업자 스레드 종료"); } static void Main() { AutoEvent = new AutoResetEvent(false); ManualEvent = new ManualResetEvent(false); Console.WriteLine("메인 스레드 시작"); Thread t1 = new Thread(DoWork1); t1.Start(); Thread t2 = new Thread(DoWork2); t2.Start(); Console.WriteLine("메인 스레드 1초 대기"); Thread.Sleep(1000); Console.WriteLine("메인 스레드 대기 끝(AutoEvent, ManualEvent 이벤트 호출)"); Console.WriteLine($"AutoEvent 호출: {AutoEvent.Set()}"); Console.WriteLine($"ManualEvent 호출: {ManualEvent.Set()}"); } } | cs |
동기화 대상
공유 자원에 대한 접근이 예상되는 스레드
한 객체를 다수의 스레드가 사용할 때
'Programming > C/C++/C#' 카테고리의 다른 글
C# 경로 가져오는 방법 (0) | 2018.01.29 |
---|---|
C# 키워드 정리 (0) | 2018.01.15 |
C# Thread.Sleep vs Task.Delay 차이 (0) | 2017.12.21 |
C# WndProc 메시지 받기. (0) | 2017.11.24 |
C# 성능 측정 (0) | 2017.09.05 |
C++ 에서 동적 메모리의 할당(malloc, new)과 해제(free,delete) 원리 (0) | 2017.08.30 |
C++ WIndow Styles (0) | 2017.08.12 |
C# 스레드 포어그라운드(Forground)와 백그라운드(Background) (0) | 2017.08.07 |