본문 바로가기
프로그래밍/c#

[c#] 쓰레드 동기화 클래스 1(Lock, Monitor)

by 그래도동 2019. 10. 8.
728x90
반응형

1. Unsafe Method : 쓰레드 동기화를 하지 않은 메서드

using System;
using System.Threading;

namespace ThreadSafe
{
    class Program
    {
        private static int baby = 0;
        
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                new Thread(CountBaby).Start();
            }
        }

        private static void CountBaby()
        {
            baby++;

            Console.WriteLine(baby);
        }
    }
}

순서없이 마음대로 찍히는 것을 볼 수 있다.

 

2. Lock

using System;
using System.Threading;

namespace ThreadSafe
{
    class Program
    {
        private static int baby = 0;
        private static object lockObj = new object();

        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                new Thread(CountBaby).Start();
            }
        }

        private static void CountBaby()
        {
            lock (lockObj)
            {
                baby++;

                Console.WriteLine(baby);
            }
        }
    }
}

lock을 사용하는 방법은 object타입으로 전역변수를 만들어주고 필요한 곳에 lock { } 구문을 넣어주면 끝!

 

결과 값

 

3. Monitor

Lock과 거의 비슷하다. 대신 Monitor.Enter(obj), Monitor.Exit(obj) 를 이용한다.

using System;
using System.Threading;

namespace ThreadSafe
{
    class Program
    {
        private static int baby = 0;
        private static object lockObj = new object();

        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                new Thread(CountBaby).Start();
            }
        }

        private static void CountBaby()
        {
            Monitor.Enter(lockObj);
            try
            {
                baby++;

                Console.WriteLine(baby);
            }
            finally
            {
                Monitor.Exit(lockObj);
            }
        }
    }
}

 

정상적인 Exit를 위해 try~finally를 이용하여 감싸준다.

결과는 Lock과 같다.

Monitor에는 wait(), pulse(), pulseAll() 이란 메서드가 있다.

wait() : 현재 쓰레드를 잠시 중단시키고, lock을 푼다. 다른 쓰레드로 pulse() 신호가 올 때까지 대기한다.

다른 쓰레드들 중 하나는 lock을 획득하여 작업을 실행한다. 작업이 끝난후 pulse()메서드를 호출하면 대기중인 쓰레드는 lock을 획득하여 작업을 실행한다.

이 메서드들은 lock 블럭 안에서 실행되어야한다.

 

using System;
using System.Threading;

namespace ThreadSafe
{
    class Program
    {
        private static int baby = 0;
        private static object lockObj = new object();

        static void Main(string[] args)
        {
            Thread anotherThrd = new Thread(AnotherCountBabyMethod);
            anotherThrd.Start();

            for (int i = 0; i < 10; i++)
            {
                new Thread(CountBaby).Start();
            }
        }

        private static void AnotherCountBabyMethod()
        {
            lock (lockObj)
            { 
                if (baby == 0) Monitor.Wait(lockObj);
                Console.WriteLine(baby);
            }
        }

        private static void CountBaby()
        {
            lock (lockObj)
            {
                baby++;
                Console.WriteLine(baby);
                Monitor.Pulse(lockObj);
            }
        }
    }
}

anotherThrd를 통해 AnotherCountBabyMethod() 메서드에 스레드가 접근했다가 wait() 때문에 대기한다.

그 뒤 for문의 첫번째 생성 쓰레드가 CountBaby() 메서드를 작업하다가 pulse() 를 만나 대기된 쓰레드를 풀어준다.

그래서 결과 값은 1이 두 번 찍히는 결과를 보여준다. 

 

 

 

 

 

 

Mutex, Semaphore를 다 정리하려 했지만 글이 길어져 다음 글에 이어서 하겠다. 

[c#] 쓰레드 동기화 클래스 2(Mutex, Semaphore)

 

 

 

 

참고

http://www.csharpstudy.com

728x90
반응형

댓글