Lock, Monitor.Wait and Pulse

seung-jae hwang·2019년 5월 9일
0

C샵

목록 보기
12/17

: Lock 이 걸린 상태에서 실행이 되고 있는데 다른 쓰레드가 들어올 경우가 가능한가??? 인데
아래 같은 경우는 그럴싸하지만 다른 예제는 이해가 안감.

Monitor의 Wait()과 Pulse()

Monitor 클래스의 또 다른 중요한 메서드로 Wait()와 Pulse() / PulseAll()이 있다.

Wait() 메서드는 현재 쓰레드를 잠시 중지하고, lock을 Release한 후, 다른 쓰레드로부터 Pulse 신호가 올 때까지 대기한다. Wait에서 lock 이 Release 되었으므로 다른 쓰레드가 lock을 획득하고 작업을 실행한다. 다른 쓰레드가 자신의 작업을 마치고 Pulse() 메서드를 호출하면 대기중인 쓰레드는 lock을 획득하고 계속 다음 작업을 실행한다.
Pulse() 메서드가 호출되었을 때, 만약 대기중인 쓰레드가 있다면, 그 쓰레드가 계속 실행하게 되지만, 만약 대기중인 쓰레드가 없다면, Pulse 신호는 없어진다.
(이러한 Wait/Pulse는 개념적으로 AutoResetEvent과 같은 이벤트 개념과 비슷하다. 하지만 AutoResetEvent는 Set() 메서드로 펄스 신호를 보내는데 대기중인 쓰레드가 없는 경우 하나의 Pulse 신호가 있었다는 것을 계속 가지고 있게 된다.)

Pulse() 메서드는 다음 한 개의 쓰레드만 계속 실행하게 하지만, PulseAll() 메서드는 현재 대기중인 모든 쓰레드를 풀어 실행하게 한다.

Monitor 클래스의 Wait(), Pulse() 메서드를 사용하기 위해 한가지 전제 조건이 있는데, 이는 이 메서드들이 lock 블럭 안에서 호출되어야 한다는 것이다.

아래 코드는 10개의 작업 쓰레드들이 데이타를 Queue에 집어 넣고, 하나의 읽기 쓰레드가 데이타를 계속 Queue에서 꺼내오는 샘플 예제이다.

예제
class Program
{
static Queue Q = new Queue();
static object lockObj = new object();
static bool running = true;

static void Main(string[] args)
{
    // reader 쓰레드 시작
    Thread reader = new Thread(ReadQueue);
    reader.Start();

    // writer 쓰레드들 시작
    List<Thread> thrds = new List<Thread>();
    for (int i = 0; i < 10; i++)
    {
        var t = new Thread(new ParameterizedThreadStart(WriteQueue));
        t.Start(i);
        thrds.Add(t);
    }
    // 모든 writer가 종료될 때까지 대기
    thrds.ForEach(p => p.Join());

    // reader 종료
    running = false;
}

static void WriteQueue(object val)
{
    lock (lockObj)
    {
        Q.Enqueue(val);
        Console.WriteLine("W:{0}", val);
        Monitor.Pulse(lockObj);                
    }
}

static void ReadQueue()
{
    while (running)
    {
        lock (lockObj)
        {
            while (Q.Count == 0)
            {
                Monitor.Wait(lockObj);
            }

            int qCount = Q.Count;
            for (int i = 0; i < qCount; i++)                
            {
                int val = (int)Q.Dequeue();
                Console.WriteLine("R:{0}", val);
            }
        }
    }
}

}

0개의 댓글