소년포비의 세계정복!!

[Thread][동기화] Event 본문

프로그램 세상/C#

[Thread][동기화] Event

소년포비 2009. 10. 6. 06:24

WaitHandle 추상 클래스로부터 상속받는 Event 관련 클래스들을 살펴 보자

 

* Event

 

지금까지는 동시에 실행되는 여러 Thread 의 공유리소스(Critical Section) 접근에 대한 동기화 관련

클래스들을 살펴 보았다.

이번 글에서는 Thread 들의 활동을 동기화 하는 방법에 대해서 알아 보자.

멀티 Threading 환경에서 동시에 수행되는 여러 Thread 들 중 특정 Thread (자신의) 작업 상태를

다른 Thread 들에게 알려주어야 할 경우가 있다.

, Thread 간의 통신을 통하여 서로의 작업 상태를 알려 주는 메커니즘을 가능케 하는 것이 Event 이다.

 

만일, 두 개의 Thread 가 있다고 가정하자(Thread1 , Thread2)

Thread1 이 자신의 작업을 완료하면 Thread2 에게 끝났다는 사실을 전달해 줘야 하며 Thread2 는 이때 자신의 작업을 수행하고

다시 Thread1에게 작업 완료를 알려줘야 하는 프로그래밍 환경에서 Event 를 사용하면 된다.

이는, 특정 작업을 처리 하기 위해 여러 Thread 들이 분할하여 수행하여야 해야 하는 경우에 유용하게 사용할 수 있다.

 

 

Event 는 아래의 두 가지 상태를 가진다

- Signaled(신호상태) / Nonsignaled(비 신호상태)

===============================================================================================================================

짐짓 헤갈릴 수 있는 부분을 명시하겠다.

기본적으로 윈도우의 리소스와 관련되는 커널 오브젝트는 Signaled 와 Nonsignaled 상태를 가진다.

만일 특정 프로세스의 커널 오브젝트 일 경우 상태는 다음과 같다.

Sinnaled : 해당 프로세스가 종료된 상태

Non-Signaled : 해당 프로세스가 실행 중인 상태

 

즉 프로세스가 첨 생성되면 커널 오브젝트가 생성되며 이 때 상태는 Non-Signaled 상태이다가 종료 시 Singaled 상태가 되는 것이다.

 

따라서 쓰레드에서의 Event 역시

Signaled(신호상태) -> 해당 쓰레드가 실행을 중지한 상태

Non-Signaled(비 신호상태) -> 해당 쓰레드가 실행 중인 상태

가 된다.

(단 프로세스에서는 한반  Signaled 가 되면 다시 Non-Signaled 상태로 변경할 수 없다)

 =====================================================================================

 

Event AutoReset , ManualReset 두 종류가 있다.

닷넷에서는 이 들 이벤트를 위해 AutoResetEvent , ManualResetEvent 클래스를 제공한다.

이 두 클래스는 모두 Win32 Event object 를 나타낸다.

 

 

이벤트의 (신호) 상태는 다음과 같이 설정한다.

-         Event.Set (상태를 Signaled로 변경) -> 쓰레드의 상태를 중지 상태로 만든다

-         Evnet.Reset (상태를 Nonsignaled로 변경) -> 쓰레드의 상태를 실행상태로 만든다

 

 

또한 Event 가 신호(Signaled) 상태가 될 때까지 대기하기 위해 WaitXXX (WaitOne,WaitAny,WaitAll) 메소드를 사용할 수 있다

 

AutoResetEvent ManualResetEvent 이 두 클래스의 차이점은 클래스 이름에서도 유추 되듯이

Reset (비신호 상태)로의 변경이 자동(묵시적)으로 되느냐 그렇지 않느냐는 차이점이 있다.

AutoResetEvent WaitXXX 메서드를 통해 신호(Signaled) 를 받으면 자동으로 비신호(Nonsignaled) 상태가 되지만

ManualResetEvent 는 명시적으로 Reset 메서드를 호출해야지만

비신호상태(Nonsignaled) 상태가 된다.

 

 

* Demo

MS 교재에 나오는 예제로 Event 의 흐름을 알아보자

Thread (PingThread,PongThread) 가 있다.

Thread 는 마치 탁구를 하듯이 ’,;을 번갈아 가면서 수행하도록 해야 한다.

이를 위해 Event 를 사용하여 두 Thread 간 통신을 통하여 구현한다.

 

class Class1

{                        

             private static AutoResetEvent pingEvent = new AutoResetEvent(false);

             private static AutoResetEvent pongEvent = new AutoResetEvent(false);

 

             [STAThread]

             static void Main(string[] args)

             {

                           Thread pingThread = new Thread(new ThreadStart(Ping));         

                           Thread pongThread = new Thread(new ThreadStart(Pong));       

                           pingThread.Start();

                           pongThread.Start();                                                                             

             }

             static void Ping()

             {

                           for(int i=0;i<10;++i)

                           {                                                   

                     //PingThread 는 자신의 일을 수행한다

                           Console.WriteLine("Ping()");

                           //PingThread 의 작업이 끝났으므로

                           //PingEvent 를 신호상태(Signaled)로 변경한다(중지 상태로 변경)

                           //PingEvent 가 신호상태가 되면 WaitOne 로 대기중이던

//PongThread 가 수행될 것이다                                              

                           pingEvent.Set();

 

                           //PongEvent 에게 신호를 받도록 한다      

                           //즉 PongEvent 가 중지상태(Signaled)가 될때 까지 기다린다           

                           pongEvent.WaitOne();

                           }

             }

             static void Pong()

             {

                           for(int i=0;i<10;++i)

                           {                                                                                                        

                                        //PingEvent 가 신호상태가 될때까지 대기한다.
                                       //즉 PingEvent 가 중지 상태(Signaled)가 될때 까지 기다린다.

                                        pingEvent.WaitOne();

 

                                        //PongThread 는 자신의 일을 수행한다

                                        Console.WriteLine("Pong()");                                   

 

                                        //PongThread 의 작업이 끝났으므로

                                        //PongEvent 를 신호상태(Signaled)로 변경한다.(중지 상태로 변경)

                                        //역시 WaitOne 로 대기중이던 PingThread 가 수행될 것이다.

                                        pongEvent.Set();

                           }

             }

}

 

- 결과

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Thread Event로 통신하면서 작업을 한번씩 번갈아 가면서 수행하는 것을 알 수 있다.

 

만일 Evnet 를 이용하지 않고 단순히 두 Thread 를 동시에 실행하면 당연하겠지만 아래와 유사하게 수행될 것이다.