프로그램/자료&정보 / / 2010. 11. 8. 09:40

쓰레드 만들기와 종료(MSDN)

반응형

http://msdn.microsoft.com/ko-kr/library/7a2f3ay4(VS.80).aspx

Visual Studio 2005

이 예제에서는 보조 또는 작업자 스레드를 만들고 기본 스레드와 함께 이 스레드를 병렬로 사용하여 작업 처리를 수행하는 방법을 보여 줍니다. 또한 다른 스레드의 작업이 끝날 때까지 한 스레드가 대기하도록 만들고 스레드를 올바르게 종료하는 방법도 보여 줍니다. 다중 스레딩에 대한 배경 정보는 관리되는 스레딩스레딩 사용(C# 프로그래밍 가이드)을 참조하십시오.

이 예제에서는 Worker라는 클래스를 만듭니다. 이 클래스에는 호출된 DoWork를 작업자 스레드가 실행하는 데 사용하는 메서드가 포함됩니다. 이는 본질적으로 작업자 스레드의 Main 함수입니다. 작업자 스레드는 이 메서드를 호출하여 실행을 시작하고 이 메서드가 반환될 때 자동으로 종료됩니다. DoWork 메서드는 다음과 같습니다.

public void DoWork()
{
    while (!_shouldStop)
    {
        Console.WriteLine("worker thread: working...");
    }
    Console.WriteLine("worker thread: terminating gracefully.");
}

Worker 클래스에는 DoWork에 반환할 시기를 알리는 데 사용되는 추가 메서드가 포함됩니다. RequestStop이라는 이 메서드는 다음과 같습니다.

public void RequestStop()
{
    _shouldStop = true;
}

RequestStop 메서드는 _shouldStop 데이터 멤버를 true에 할당하기만 합니다. 이 데이터 멤버는 DoWork 메서드에서 검사하므로 이는 DoWork의 반환을 통해 작업자 스레드를 종료하는 결과를 가져옵니다. 그러나 중요한 점은 DoWorkRequestStop이 서로 다른 스레드에서 실행된다는 사실입니다. DoWork는 작업자 스레드에서 실행되고 RequestStop은 기본 스레드에서 실행되므로 _shouldStop 데이터 멤버는 다음과 같이 volatile로 선언됩니다.

private volatile bool _shouldStop;

volatile 키워드는 여러 스레드가 _shouldStop 데이터 멤버에 액세스하므로 이 멤버의 상태에 대한 최적화 가정을 하지 말아야 한다는 사실을 컴파일러에 경고로 알립니다. 자세한 내용은 volatile(C# 참조)을 참조하십시오.

_shouldStopbool인 경우 volatile_shouldStop 데이터 멤버와 함께 사용하면 형식 스레드 동기화 기술을 사용하지 않고도 여러 스레드에서 이 멤버에 안전하게 액세스할 수 있습니다. 즉, 한 번의 단일 원자 연산만으로 _shouldStop을 수정할 수 있습니다. 그러나 이 데이터 멤버가 클래스, 구조체 또는 배열인 경우 여러 스레드에서 이 멤버에 액세스하면 간헐적으로 데이터가 손상될 수 있습니다. 배열의 값을 변경하는 스레드를 생각해 볼 수 있습니다. Windows에서는 다른 스레드를 실행할 수 있도록 스레드를 정기적으로 중단하므로 일부 배열 요소는 할당했지만 다른 요소를 아직 할당하지 않은 상태에서 이 스레드가 중단될 수 있습니다. 이 경우 배열의 상태는 프로그래머가 의도한 것과 전혀 다르므로 이 배열을 읽는 다른 스레드의 작업이 실패할 수 있습니다.

작업자 스레드를 실제로 만들기 전에 Main 함수에서 Worker 개체와 Thread의 인스턴스를 만듭니다. 스레드 개체는 Worker.DoWork 메서드에 대한 참조를 다음과 같이 Thread 생성자에 전달하여 이 메서드를 진입점으로 사용하도록 구성됩니다.

Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);

이 시점에서 작업자 스레드 개체가 존재하고 구성된 상태이지만 실제 작업자 스레드는 아직 작성되지 않습니다. 실제 작업자 스레드는 Main에서 Start 메서드를 호출해야 작성됩니다.

workerThread.Start();

이제 시스템에서 작업자 스레드의 실행을 초기화하지만 이 과정은 기본 스레드에 대해 비동기적으로 수행됩니다. 즉, Main 함수는 작업자 스레드를 동시에 초기화하는 동안 코드를 계속하여 즉시 실행합니다. 작업자 스레드가 실행되기도 전에 Main 함수가 이 스레드를 종료하지 않도록 하기 위해 Main 함수는 작업자 스레드 개체의 IsAlive 속성이 true로 설정될 때까지 반복됩니다.

while (!workerThread.IsAlive);

그런 다음 Sleep을 호출하여 기본 스레드가 잠시 중단됩니다. 이렇게 하면 Main 함수가 다른 명령을 실행하기 전에 작업자 스레드의 DoWork 함수에서 DoWork 메서드 안의 루프를 몇 차례 반복하여 실행할 수 있습니다.

Thread.Sleep(1);

1밀리초가 경과하면 Main은 앞서 가져온 Worker.RequestStop 메서드를 사용하여 작업자 스레드 개체를 종료하도록 신호를 보냅니다.

workerObject.RequestStop();

Abort를 호출하여 다른 스레드에서 스레드를 종료할 수도 있지만 대상 스레드를 이와 같이 강제로 종료하면 해당 스레드의 작업이 완료되었는지 확인할 수 없을 뿐 아니라 리소스를 정리할 수도 없습니다. 따라서 이 예제에서 설명하는 방법을 사용하는 것이 더 좋습니다.

마지막으로, Main 함수가 작업자 스레드 개체에 대한 Join 메서드를 호출하니다. 이 메서드는 개체가 가리키는 스레드가 종료될 때까지 현재 스레드를 차단하거나 대기 상태로 만듭니다. 따라서 Join은 작업자 스레드가 반환되고 자체 종료될 때까지 반환되지 않습니다.

workerThread.Join();

이 단계에서는 Main을 실행하는 기본 스레드만 남게 됩니다. 이 스레드는 최종 메시지 하나를 표시한 다음 반환되어 기본 스레드를 함께 종료합니다.

완성된 예제는 다음과 같습니다.

예제

using System;
using System.Threading;

public class Worker
{
    // This method will be called when the thread is started.
    public void DoWork()
    {
        while (!_shouldStop)
        {
            Console.WriteLine("worker thread: working...");
        }
        Console.WriteLine("worker thread: terminating gracefully.");
    }
    public void RequestStop()
    {
        _shouldStop = true;
    }
    // Volatile is used as hint to the compiler that this data
    // member will be accessed by multiple threads.
    private volatile bool _shouldStop;
}

public class WorkerThreadExample
{
    static void Main()
    {
        // Create the thread object. This does not start the thread.
        Worker workerObject = new Worker();
        Thread workerThread = new Thread(workerObject.DoWork);

        // Start the worker thread.
        workerThread.Start();
        Console.WriteLine("main thread: Starting worker thread...");

        // Loop until worker thread activates.
        while (!workerThread.IsAlive);

        // Put the main thread to sleep for 1 millisecond to
        // allow the worker thread to do some work:
        Thread.Sleep(1);

        // Request that the worker thread stop itself:
        workerObject.RequestStop();

        // Use the Join method to block the current thread
        // until the object's thread terminates.
        workerThread.Join();
        Console.WriteLine("main thread: Worker thread has terminated.");
    }
}

샘플 출력

main thread: starting worker thread...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: working...
worker thread: terminating gracefully...
main thread: worker thread has terminated

참고 항목

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유