본문 바로가기
Programing_Language/C#

[쓰레드 동기화] Monitor 와 lock (IPC) (lock > Monitor 편의성)

by neohtux 2020. 7. 18.
728x90

https://docs.microsoft.com/ko-kr/dotnet/api/system.threading.monitor?view=netcore-3.1

 

Monitor Class (System.Threading)

개체에 대한 액세스를 동기화하는 메커니즘을 제공합니다.Provides a mechanism that synchronizes access to objects.

docs.microsoft.com

Monitor

Interlock과 같이 공유 자원 선점의 동기화를 위해 사용된다.

 

Interlock의 경우 특정 쓰레드 동기화가 필요한 코드 블럭 { 임 계 구 역 }  

을 동기화 할때 쓰기보다는 특정 변수의 Increment 와 Decrement를 할 때 많이 쓰인다.

 

코드 블럭단위의 임계구역의 진입을 제어하기 위해  Monitor와 lock 이 제공된다.

 

여기서 사용되는 object obj 는 세마포어에서 비유되는 자물쇠와 같은 역할이다

 

P() , V() ,

Semaphore(obj) RS = obj

P(); 
//
if (RS >0 then RS= RS-1;
else block();
//

 {

  임계구역

}

V()
//
RS=RS+1;
wake_up();
//

 

Monitor의 경우 사용 예제

 static int num = 0;
        static object _lock = new object();

        static void Thread_1()
        {
            for (int i = 0; i < 100000; ++i)
            {

                Monitor.Enter(_lock);
                num++;
                Monitor.Exit(_lock);
            }
                
        }
        static void Thread_2()
        {
            for (int i = 0; i < 100000; ++i)
            {
                Monitor.Enter(_lock);
                num--;
                Monitor.Exit(_lock);
            }
                
        }
        static void Main(string[] args)
        {

            Thread t1 = new Thread(Thread_1);
            Thread t2 = new Thread(Thread_2);

            t1.Start();
            t2.Start();

            t1.Join();
            t2.Join();
            Console.WriteLine(num);
        }

 

하지만, 만약 임계구역내에 break; 문이 있어서 Enter(_lock) 이후

Exit (wake_up) 상태로 _lock을 전이 시켜주지 못하면 데드락(교착상태) 에 빠질 위험이 생길수도 있다

다음과 같이 해결 할 수도 있지만.

try
                {
                    Monitor.Enter(_lock);
                    num++;

                }
                finally
                {
                    Monitor.Exit(_lock);
                }

 

이 경우 사용의 편의성이 더 좋은 녀석이 있다.

lock

lock의 장점

 1. 모니터(세마포어)와 마찬가지로 상호배제 역할 수행

 2. 동기화가 이루어지지 않아 Exit 신호를 기다리며 대기큐에 교착상태의 실수를 줄일 수 있다.

 3. 좀 더 보기 편하다.

 static int num = 0;
        static object _lock = new object();

        static void Thread_1()
        {
            for (int i = 0; i < 100000; ++i)
            {
                lock(_lock)
                {
                    num++;
                }
              
            }
                
        }
        static void Thread_2()
        {
            for (int i = 0; i < 100000; ++i)
            {
                Monitor.Enter(_lock);
                num--;
                Monitor.Exit(_lock);
            }
                
        }
        static void Main(string[] args)
        {

            Thread t1 = new Thread(Thread_1);
            Thread t2 = new Thread(Thread_2);

            t1.Start();
            t2.Start();

            t1.Join();
            t2.Join();
            Console.WriteLine(num);
        }

 

300x250

댓글