이 포스트에서는 C#에서 발생하는 ThreadStateException 에러의 상세한 원인 및 해결 방법을 알아보겠습니다.
문제상황
다음과 같은 코드를 사용하여 멀티스레딩 작업을 수행하려고 합니다.
using System;
using System.Threading;
class Program
{
static void Main()
{
Thread thread = new Thread(new ThreadStart(DoWork));
thread.Start();
thread.Suspend();
thread.Resume();
}
static void DoWork()
{
Console.WriteLine("Hello, World!");
}
}
위 코드는 메인 스레드에서 DoWork 메서드를 실행하는 새로운 스레드를 생성하고 시작합니다. 그런 다음 Suspend() 메서드를 사용하여 스레드를 일시 중지하고 Resume() 메서드를 사용하여 스레드를 다시 시작합니다.
에러로그 내용:
Unhandled Exception: System.Threading.ThreadStateException: Thread is not in the correct state for the method to be called.
원인분석
ThreadStateException은 스레드가 메서드를 호출하기에 적절한 상태가 아닐 때 발생하는 에러입니다. 이 에러는 일반적으로 스레드가 이미 종료되었거나 아직 시작되지 않은 상태에서 일부 스레드 메서드를 호출할 때 발생합니다.
이 경우, 에러는 Suspend() 메서드를 호출할 때 발생합니다. 이 메서드는 현재 스레드를 일시 중지시키기 위한 기능을 제공하지만, 스레드가 완전히 시작되기 전에 호출되기 때문에 ThreadStateException이 발생합니다. 그러므로 이 문제를 해결하려면 스레드가 완전히 시작된 후에만 Suspend()와 Resume() 메서드를 호출해야 합니다.
해결방법-1 (ManualResetEvent 사용)
첫 번째 해결 방법은 ManualResetEvent를 사용하여 스레드가 완전히 시작되기 전에 Suspend()와 Resume() 메서드를 호출하는 것을 막을 수 있습니다. 다음은 수정된 코드 예입니다.
using System;
using System.Threading;
class Program
{
static ManualResetEvent threadStartedEvent = new ManualResetEvent(false);
static void Main()
{
Thread thread = new Thread(new ThreadStart(DoWork));
thread.Start();
threadStartedEvent.WaitOne(); // Wait for the thread to start
thread.Suspend();
thread.Resume();
}
static void DoWork()
{
threadStartedEvent.Set(); // Signal that the thread has started
Console.WriteLine("Hello, World!");
}
}
위 코드에서 ManualResetEvent 객체인 threadStartedEvent를 사용하여 스레드가 시작되면 신호를 보냅니다. 이후 메인 스레드에서 WaitOne() 메서드를 호출하여 스레드가 시작될 때까지 기다립니다. 이렇게 하면 Suspend()와 Resume() 메서드가 스레드가 완전히 시작된 후에만 호출되므로 ThreadStateException이 발생하지 않습니다.
해결방법-2 (Thread.Join 사용)
두 번째 해결 방법은 Thread.Join을 사용하여 스레드가 완전히 시작되기 전에 메인 스레드가 실행을 중단하도록 할 수 있습니다. 다음은 수정된 코드 예입니다.
using System;
using System.Threading;
class Program
{
static void Main()
{
Thread thread = new Thread(new ThreadStart(DoWork));
thread.Start();
Thread.Sleep(100); // Give the new thread some time to start
thread.Suspend();
thread.Resume();
thread.Join(); // Wait for the thread to finish
}
static void DoWork()
{
Console.WriteLine("Hello, World!");
}
}
위 코드에서 메인 스레드는 Thread.Sleep(100)을 호출하여 충분한 시간 동안 실행을 중단하고 새 스레드가 시작되기를 기다립니다. 이렇게 하면 Suspend()와 Resume() 메서드가 스레드가 완전히 시작된 후에만 호출되므로 ThreadStateException이 발생하지 않습니다. 마지막으로 thread.Join()을 호출하여 스레드가 완료될 때까지 메인 스레드가 기다립니다.