스레드의 상태 변화는 사람의 인생처럼 다양한 단계를 거친다.
.NET은 스레드의 상태를 ThreadState 열거형에 정의해 두었다.
Unstarted): 스레드가 처음 생성된 상태(Thread 객체를 생성한 직후의 상태)입니다. 아직 아무런 일도 하지 않습니다. Ready): 스레드가 실행될 준비를 마친 상태입니다. CPU의 시간을 할당받기를 기다립니다. Running): CPU가 스레드에 시간을 할당하여 스레드가 실행되는 상태입니다. Start() 메서드를 호출하여 스레드를 시작하면 Running 상태가 됩니다.Suspended): 스레드가 잠시 멈춘 상태입니다. 다른 스레드가 작업을 완료할 때까지 기다리거나, 특정 조건이 만족될 때까지 기다립니다. Suspend() 메서드를 호출하면 Suspended 상태가 됩니다. .NET 5 이상에서는 더 이상 사용되지 않습니다.Blocked): 스레드가 외부 자원(파일, 네트워크 등)을 기다리는 상태입니다. Stopped): 스레드가 작업을 완료하거나 비정상적으로 종료된 상태입니다. 스레드가 return 문을 만나거나 예외가 발생하면 Stopped 상태가 됩니다.이러한 상태 변화는 운영체제의 스케줄러에 의해 관리됩니다. 스케줄러는 CPU 시간을 각 스레드에 적절히 분배하여 여러 스레드가 동시에 실행되는 것처럼 보이도록 합니다.
좀 더 쉽게 이해하려면, 놀이공원의 놀이기구를 떠올리면 됩니다.
Unstarted: 놀이기구가 운행을 시작하기 전 상태입니다.Ready: 놀이기구에 탑승할 손님들이 줄을 서서 기다리는 상태입니다.Running: 놀이기구가 운행 중인 상태입니다.Suspended: 놀이기구가 잠시 멈춘 상태입니다. (예: 안전 점검)Blocked: 놀이기구가 고장나서 멈춘 상태입니다.Stopped: 놀이기구 운행이 종료된 상태입니다.스레드의 상태 변화를 이해하면 프로그램의 동작 방식을 더 잘 이해하고, 스레드를 효율적으로 사용할 수 있습니다.
스레드의 상태 변화에는 규칙이 있습니다.
스레드 상태 전이
스레드는 실행되는 동안 여러 상태를 거치게 됩니다. 예를 들어, Thread 객체를 생성하면 Unstarted 상태가 되고, Start() 메서드를 호출하면 Running 상태가 됩니다. Sleep() 메서드를 호출하면 WaitSleepJoin 상태가 되고, Sleep() 메서드가 반환되면 다시 Running 상태가 됩니다.
스레드 상태 확인
Thread.ThreadState 프로퍼티를 사용하여 스레드의 현재 상태를 확인할 수 있습니다.
스레드 상태의 활용
스레드의 상태를 확인하고 제어하여 프로그램의 동작을 조정할 수 있습니다. 예를 들어, 스레드가 특정 상태가 될 때까지 기다리거나, 스레드를 일시 중지하거나, 스레드를 중단할 수 있습니다.
참고
Flags 애트리뷰트
ThreadState열거형은 Flags 애트리뷰트를 갖고 있습니다.. Flags는 자신이 수식하는 열거형을 비트 필드(Bit Field), 즉 플래그 집합으로 처리할 수 있음을 나타냅니다.
비트 필드
비트 필드(Bit Field)는 C 언어 등에서 구조체를 선언할 떄, 바이트 단위가 아닌 '비트 단위로 선언한 필드'를 말합니다. 비트 필드는 주로 비트 단위의 플래그(Bit Flag)를 표현하기 위해 사용했습니다. 왜냐하면 1 바이트로 0~255까지 표현할 수 있는데, 0, 1, 2, 3, ..., 7 정도의 값을 갖는 플래그를 표현하기 위해 1 바이트를 통째로 사용하는 것은 아까웠기 때문입니다.
이처럼 C에서 사용되던 비트 필드를 C#에 적용하기 위해 .NET에 Flags 애트리뷰트를 선언해둔 것입니다.
스레드의 상태를 표현할 때 비트 필드를 사용하는 경우가 있습니다. 비트 필드는 하나의 변수에 여러 개의 불리언 값을 저장하는 기법입니다. 각 비트가 하나의 불리언 값을 나타내므로, 메모리를 효율적으로 사용할 수 있다는 장점이 있습니다.
예를 들어, 스레드의 상태가 "실행 중", "대기 중", "블록됨"과 같은 여러 상태를 가질 수 있다고 가정해 보겠습니다. 이러한 상태를 표현하기 위해 각 상태에 해당하는 불리언 변수를 사용하면 3개의 변수가 필요합니다. 하지만 비트 필드를 사용하면 하나의 정수형 변수로 스레드의 상태를 표현할 수 있습니다.
00000001 (1) : 실행 중
00000010 (2) : 대기 중
00000100 (4) : 블록됨
각 비트는 스레드의 특정 상태를 나타냅니다. 예를 들어, 첫 번째 비트가 1이면 "실행 중" 상태를 의미합니다.
비트 필드를 사용하면 메모리를 절약할 수 있을 뿐만 아니라, 비트 연산을 사용하여 스레드의 상태를 효율적으로 변경하고 확인할 수 있습니다.
예를 들어, 스레드를 "대기 중" 상태로 변경하려면 다음과 같이 비트 OR 연산을 사용할 수 있습니다.
state |= 2; // state 변수의 두 번째 비트를 1로 설정
스레드가 "블록됨" 상태인지 확인하려면 다음과 같이 비트 AND 연산을 사용할 수 있습니다.
if ((state & 4) != 0) { ... } // state 변수의 세 번째 비트가 1인지 확인
비트 필드는 C#에서 Flags 특성(애트리뷰트)을 사용하여 열거형으로 정의할 수 있습니다.
[Flags]
enum ThreadState
{
Running = 1,
Waiting = 2,
Blocked = 4
}
Flags 애트리뷰트는 열거형에 적용되어, 열거형 멤버들을 비트 플래그로 처리할 수 있도록 합니다. 즉, 하나의 변수에 여러 개의 열거형 값을 비트 OR 연산으로 결합하여 저장할 수 있습니다.
ThreadState 열거형은 Unstarted, Running, WaitSleepJoin, Stopped, AbortRequested, Aborted 등의 값을 가집니다.
예를 들어, 스레드가 실행 중이면서 동시에 일시 중단된 상태라면 ThreadState.Running | ThreadState.Suspended와 같이 표현할 수 있습니다.
Flags 애트리뷰트는 열거형의 요소들의 집합으로 구성되는 값들을 표현할 수 있도록 해주는 유용한 기능입니다. 특히 스레드의 상태처럼 여러 상태가 동시에 존재할 수 있는 경우 유용하게 사용할 수 있습니다.
ThreadState의 요소값
ThreadState 열거형은 Flags 애트리뷰트를 사용하여 정의되어 있으며, 각 멤버는 2의 거듭제곱 값을 가집니다.
[Flags]
public enum ThreadState
{
Running = 0,
StopRequested = 1,
SuspendRequested = 2,
Background = 4,
Unstarted = 8,
Stopped = 16,
WaitSleepJoin = 32,
Suspended = 64,
AbortRequested = 128,
Aborted = 256,
}
이렇게 각 멤버가 2의 거듭제곱 값을 가지면, 각 멤버는 하나의 비트를 나타내므로 여러 상태를 비트 OR 연산(|)을 통해 하나의 변수에 저장할 수 있습니다.
예를 들어, 스레드가 Running 상태이면서 Background 상태인 경우, ThreadState 값은 Running | Background (즉, 0 | 4 = 4)가 됩니다.
.NET이 ThreadState를 2의 제곱으로 증가하는 값으로 정의해 둔 이유는 무엇일까?
2의 제곱을 2진수로 바꾸면 항상 한 자리만 1이고 나머지는 0으로 채워지기 때문입니다. 비트 연산을 통해 ThreadState가 현재 어떤 상태인지 쉽게 파악 할 수 있습니다.
(Running 상태는 10진수로는 '0' 이지만, 2진수로는 '00000000',
SuspendRequested 상태는 10진수로는 '2'이지만, 2진수로는 '00000010')
비트 필드와 Flags 애트리뷰트
스레드의 상태를 표현할 때, 여러 상태를 동시에 나타낼 수 있도록 비트 필드와 Flags 애트리뷰트를 사용하는 경우가 있어요.
비트 필드는 하나의 정수 변수에 여러 개의 불리언 값을 저장하는 기술입니다. 각 비트는 특정 상태를 나타내고, 비트 연산을 사용하여 여러 상태를 동시에 표현할 수 있습니다.
Flags 애트리뷰트는 열거형에 적용하여 각 열거형 값이 비트 필드로 사용될 수 있도록 합니다. 즉, 여러 개의 열거형 값을 비트 OR 연산으로 결합하여 여러 상태를 동시에 표현할 수 있습니다.
예시
[Flags]
enum ThreadState
{
Running = 0x01,
Suspended = 0x02,
Waiting = 0x04,
Aborted = 0x08
}
ThreadState state = ThreadState.Running | ThreadState.Waiting; // Running과 Waiting 상태를 동시에 표현
이 코드에서 ThreadState 열거형은 Flags 애트리뷰트를 사용하여 각 값이 비트 필드로 사용될 수 있도록 합니다. state 변수는 Running과 Waiting 상태를 동시에 나타냅니다.
비트 필드와 Flags 애트리뷰트를 사용하는 이유
Flags 애트리뷰트를 사용하면 상태를 나타내는 코드를 더욱 읽기 쉽게 만들 수 있습니다.참고
Flags 애트리뷰트를 사용하려면 열거형의 기반 타입이 정수형이어야 합니다.비트 필드와 Flags 애트리뷰트는 스레드의 상태를 효율적으로 표현하는 데 유용하게 사용될 수 있습니다.
using System;
using System.Threading; // 스레드 사용을 위한 네임스페이스
namespace UsingThreadState
{
class MainApp
{
private static void PrintThreadState(ThreadState state) // ThreadState 값과 해당하는 정수 값을 출력하는 메서드
{
Console.WriteLine("{0,-16} : {1}", state, (int)state);
}
static void Main(string[] args)
{
PrintThreadState(ThreadState.Running); // Running 상태 출력
PrintThreadState(ThreadState.StopRequested); // StopRequested 상태 출력
PrintThreadState(ThreadState.SuspendRequested); // SuspendRequested 상태 출력
PrintThreadState(ThreadState.Background); // Background 상태 출력
PrintThreadState(ThreadState.Unstarted); // Unstarted 상태 출력
PrintThreadState(ThreadState.Stopped); // Stopped 상태 출력
PrintThreadState(ThreadState.WaitSleepJoin); // WaitSleepJoin 상태 출력
PrintThreadState(ThreadState.Suspended); // Suspended 상태 출력
PrintThreadState(ThreadState.AbortRequested); // AbortRequested 상태 출력
PrintThreadState(ThreadState.Aborted); // Aborted 상태 출력
PrintThreadState(ThreadState.Aborted | ThreadState.Stopped); // Aborted | Stopped 상태 출력
}
}
}
코드 설명
이 C# 코드는 ThreadState 열거형의 각 멤버를 출력하는 예제입니다. ThreadState 열거형은 스레드의 현재 상태를 나타냅니다.
PrintThreadState(ThreadState state) 메서드는 ThreadState 값과 해당하는 정수 값을 출력합니다.Main 메서드는 ThreadState 열거형의 각 멤버를 PrintThreadState 메서드에 전달하여 출력합니다.출력 결과
Running : 0
StopRequested : 1
SuspendRequested : 2
Background : 4
Unstarted : 8
Stopped : 16
WaitSleepJoin : 32
Suspended : 64
AbortRequested : 128
Aborted : 256
Aborted : 272
ThreadState 열거형
Running: 스레드가 실행 중입니다.StopRequested: 스레드가 중지 요청을 받았습니다.SuspendRequested: 스레드가 일시 중단 요청을 받았습니다.Background: 스레드가 백그라운드 스레드입니다.Unstarted: 스레드가 아직 시작되지 않았습니다.Stopped: 스레드가 중지되었습니다.WaitSleepJoin: 스레드가 대기, 절전 또는 다른 스레드에 조인 중입니다.Suspended: 스레드가 일시 중단되었습니다.AbortRequested: 스레드가 중단 요청을 받았습니다.Aborted: 스레드가 중단되었습니다.참고
ThreadState 열거형은 Flags 특성(애트리뷰트)을 가지고 있으므로, 여러 상태를 비트 OR 연산자(|)를 사용하여 결합할 수 있습니다.Thread.ThreadState 프로퍼티를 사용하여 스레드의 현재 상태를 가져올 수 있습니다.