Hyokyun Yim bio photo

Hyokyun Yim

Koreatech Computer Science Engineering undergraduate 4 grade.

Facebook Github

스레드의 동기화 이해를 위해 C#의 Monitor class 를 이용하여 코드를 작성해 보겠다.

Overview

Monitor class

  • .NET Framwork 에서 제공하는 Monitor 클래스를 활용하여 스레드의 동기화에대해 좀 더 자세히 이해해 보겠다.
  • Monitor class 의 네임스페이스는 System.Threading 에 있다
  • 자세한 사용법은 MSDN 참고
  • 기본적인 함수로 Monitor.Enter() , Monitor.Exit() 이다.
  • Monitor.Enter()는 지정된 스레드를 잠궈서 Critical Section 에 다른 쓰레드가 침입하지 못하도록 한다
  • Monitor.Exit()는 지정된 스레드를 해제하여 다음 쓰레드가 Critical Section 을 수행할 수 있게 한다.

Monitor class 예제 1


using System;
using System.IO;
using System.Threading;

namespace monitorclass
{
class Program
    {

        static object locker = new object();
        static void ThreadMain()
        {
            for (int i = 0; i < 50000; i++)
                for (int j = 0; j < 50000; j++) ;        

             WriteToFile();                              // 공유 리소스에 접근 - critical section
        }
        static void WriteToFile()
        {
            String ThreadName = Thread.CurrentThread.Name;
            Console.WriteLine("{0} using Resource", ThreadName);
            Monitor.Enter(locker);                       // 모니터에 들어감
            try
            {
                using (StreamWriter sw = new StreamWriter(@"C:\Users\hyokyun\Documents/hoho.txt", true))
               {   
                   sw.WriteLine(ThreadName);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                Monitor.Exit(locker);                  // 모니터에서 나옴
                Console.WriteLine("{0} releasing Resource", ThreadName);
            }
        }
        static void Main(string[] args)
        {
            for (int i = 0; i < 3; i++)
            {
                Thread thread = new Thread(new ThreadStart(ThreadMain));
                thread.Name = String.Concat("Thread - ", i);
                thread.Start();
                
            }
            Console.Read();
        }
    }
}
  • 생성된 3개의 쓰레드가 하나의 파일(공유 자원)에 접근하기 위한 소스코드 이다.
  • 한 쓰레드가 작업을 진행하기 전에 Monitor.Enter() 호출하여 Monitor 에들어가 작업을 하는동안에는 다른 쓰레드가 접근할 수 없다.
  • Monitor.Exit() 를 호출하여 Monitor 에서 나오면 공유자원을 해제하고 다음 쓰레드에게 자원을 넘긴다.
  • 결과가 꼭 쓰레드 0, 쓰레드 1, 쓰레드 2 순서로 출력되진 않는다. 쓰레드가 꼭 생성된 순서대로 실행되는것으 아니기 때문이다.

montior class 예제 2


using System;
using System.Threading;

namespace waitndpulesmethod
{
    class TickTock
    {
        public void tick(bool running)
        {
            lock (this)
            {
                if (!running)
                {  //  틱이 다 끝났다면 정지함    
                    Monitor.Pulse(this);  //  나머지 스레드에게 알리고   
                    return;               //  리턴으로 빠져 나온다.
                }
                Console.Write("Tick  ");
                Monitor.Pulse(this);  // tock 스레드에게 다음에 너가 수행하라고 알린다.  
                Monitor.Wait(this);  //  tick 자기는 wait상태로 간다.
            }
        }
        public void tock(bool running)
        {
            lock (this)
            {
                if (!running)
                {  //  톡이 다 끝났다면 정지함    
                    Monitor.Pulse(this);  //  나머지 스레드에게 알리고
                    return;               //  리턴으로 빠져 나온다.
                }
                Console.WriteLine("Tock");
                Monitor.Pulse(this);  //  tick 스레드에게 다음에 너가 수행하라고 알린다.    
                Monitor.Wait(this);  //   tock 자기는 wait 상태로 간다.
            }
        }
    }
    class MyThread
    {
        public Thread thrd;
        TickTock ttOb;
        //  Construct  a  new  thread.    
        public MyThread(string name, TickTock tt)
        {
            thrd = new Thread(this.run);
            ttOb = tt;
            thrd.Name = name;
            thrd.Start();
        }
        //  Begin  execution  of  new  thread.    
        void run()
        {
            if (thrd.Name == "Tick")
            {
                for (int i = 0; i < 5; i++) ttOb.tick(true);
                ttOb.tick(false);
            }
            else
            {
                for (int i = 0; i < 5; i++) ttOb.tock(true);
                ttOb.tock(false);
            }
        }
    }
    class TickingClock
    {
        public static void Main()
        {
            TickTock tt = new TickTock();
            MyThread mt1 = new MyThread("Tick", tt);
            MyThread mt2 = new MyThread("Tock", tt);

            mt1.thrd.Join();
            mt2.thrd.Join();
            Console.WriteLine("Clock  Stopped");
            Console.Read();
        }
    }
}
  • Monitor.Pulse() 와 Monitor.Wait() 를 사용한 예제이다
  • Monitor.Pulse()는 대기 중인 큐에 포함된 스레드에 잠겨 있는 개체의 상태 변경을 알린다.(condition 변수의 signal() 과 같다고 보면 될것 같다)
  • Monitor.Wait()는 개체의 잠금을 해제한 다음 잠금을 다시 가져올 때까지 현재 스레드를 차단한다.