C#

[C#]Thread 생성자(Thread Constructor)

DevStory 2022. 5. 28.

스레드(Thread)란?

스레드는 프로세스의 단위입니다. 실행되고 있는 프로그램을 프로세스라고 하며, 한 개의 프로세스로 프로그램을 실행하기 어렵기 때문에 프로세스를 여러 단위(=스레드)로 나누어 프로그램을 효율적으로 실행하도록 합니다.

 

프로세스에는 기본적으로 스레드가 하나 이상 있으며, 이 스레드를 기본 스레드, 단일 스레드, 싱글 스레드라고 말합니다. 프로세스에 여러 개의 스레드가 존재하면 멀티 스레드라고 말합니다.


Thread 클래스의 역할

스레드 생명 주기가 시작되면, Thread 클래스의 객체가 생성됩니다. 스레드 생명 주기가 끝나거나 작업을 완료되었으면 Thread의 실행이 중단되거나 종료됩니다.

 

다음은 스레드 생명 주기의 상태입니다.


생성(Create) 상태

Thread 객체를 생성했지만, Start() 메서드가 호출되지 않은 상태입니다.


준비(Ready) 상태

Thread가 실행되기 위해 모든 설정이 완료되었으나 CPU를 할당받지 않아 준비 중인 상태입니다.


대기 상태

  • Sleep() 혹은 Wait() 메서드가 호출되어 대기 중인 상태입니다.
  • 입출력(I/O) 이벤트에 의해 실행이 차단(Block)된 상태입니다.

죽은(Dead) 상태

죽은 상태는 스레드의 실행이 완료되거나 프로그램이 메모리에서 해제된 상태입니다.


Thread 생성자(Constructor)

C#의 Thread 클래스에는 다음과 같이 네 개의 생성자가 존재합니다.

public Thread(ParameterizedThreadStart start);
public Thread(ThreadStart start);
public Thread(ParameterizedThreadStart start, int maxStackSize);
public Thread(ThreadStart start, int maxStackSize);

생성자의 매개변수로 ParameterizedThreadStart와 ThreadStart 타입이 존재합니다. 두 개의 타입은 delegate 키워드로 선언되었으므로 대리자라는 것을 알 수 있습니다.

namespace System.Threading
{
  public delegate void ThreadStart();
}

ParameterizedThreadStart와 ThreadStart는 대리자이므로 Thread 생성자에 메서드를 전달할 수 있습니다.

 

다음 예제는 Thread 클래스 생성자에 PrintValue() 메서드를 전달합니다. Start() 메서드를 호출하여 대리자에 의해 PrintValue() 메서드가 실행되는 것을 보여줍니다.

class Program
{
  public static void PrintValue()
  {
    for(int num = 0; num < 3; num++)
    {
      Console.WriteLine("num: " + num);
    }
  }

  static void Main(string[] args)
  {
    Thread thread = new Thread(PrintValue);
    thread.Start();
  }
}

실행 결과

num: 0
num: 1
num: 2

대리자에 의해 메서드가 실행되므로 Thread 생성자에 람다식을 작성할 수 있습니다. 다음 예제는 PrintValue() 메서드를 제거하고 Thread 생성자에 람다식을 작성합니다.

class Program
{
  static void Main(string[] args)
  {
    Thread thread = new Thread(() => {
        for (int num = 0; num < 3; num++)
        {
            Console.WriteLine("num: " + num);
        }
    });
    thread.Start();
  }
}

실행 결과

num: 0
num: 1
num: 2

매개변수가 있는 메서드

다음 예제는 하나의 매개변수가 존재하는 메서드를 Thread 클래스 생성자에 전달합니다.

class Program
{
  public void PrintValue(Object maxLoop)
  {
    int Number = Convert.ToInt32(maxLoop);

    for (int num = 0; num < Number; num++)
    {
      Console.WriteLine("num: " + num);
    }
  }

  static void Main(string[] args)
  {
    Program program = new Program();
    Thread thread = new Thread(program.PrintValue);
    thread.Start(5);
  }
}

실행 결과

num: 0
num: 1
num: 2
num: 3
num: 4

하나의 매개변수를 가지는 메서드는 ParameterizedThreadStart 대리자에 의해 실행됩니다.

 

다음은 ParameterizedThreadStart 대리자의 정의입니다.

namespace System.Threading
{
  public delegate void ParameterizedThreadStart(object? obj);
}

Object 타입의 매개변수를 가지므로 PrintValue() 메서드의 매개변수도 Object 타입으로 정의합니다. ThreadStart 대리자와 마찬가지로 어떠한 값도 반환하지 않으며, 다음과 같이 람다식을 전달할 수 있습니다.

class Program
{
  static void Main(string[] args)
  {
    Program program = new Program();
    Thread thread = new Thread((value) => {
        int Number = Convert.ToInt32(value);

        for (int num = 0; num < Number; num++)
        {
          Console.WriteLine("num: " + num);
        }
    });
    thread.Start(5);
  }
}

즉, 메서드에 매개변수가 존재하는 경우 ThreadStart 대리자가 동작하며, 그렇지 않으면 ParameterizedThreadStart 대리자가 동작합니다.


ParameterizedThreadStart 대리자의 문제점

ParameterizedThreadStart 대리자 정의에서 알 수 있듯이 매개변수의 타입은 Object입니다. 따라서, 타입 변환이 필요합니다.

 

다음 예제는 Start() 메서드에 문자열 값을 전달하고 컴파일 에러가 발생하는 것을 보여줍니다.

class Program
{
  public void PrintValue(Object maxLoop)
  {
    int Number = Convert.ToInt32(maxLoop);

    for (int num = 0; num < Number; num++)
    {
      Console.WriteLine("num: " + num);
    }
  }

  static void Main(string[] args)
  {
    Program program = new Program();
    Thread thread = new Thread(program.PrintValue);
    thread.Start("Hello");
  }
}

실행 결과

ParameterizedThreadStart 대리자의 문제는 타입 변환이 실패하면 런타임 에러가 발생하므로 안전하지 않다는 것입니다.


정리

  • 스레드는 프로세스의 단위입니다.
  • 스레드 생성자에 메서드를 전달할 수 있습니다.
  • 스레드 생성자에 람다식을 전달할 수 있습니다.
  • 매개변수가 없는 메서드는 ThreadStart 대리자에 의해 실행됩니다.
  • 하나의 매개변수가 존재하는 메서드는 ParameterizedThreadStart 대리자에 의해 실행됩니다.
  • ParameterizedThreadStart 대리자는 Object 타입의 매개변수를 가지므로 타입 변환이 필수적이며, 안전하지 않습니다.
반응형

'C#' 카테고리의 다른 글

[C#]지역 함수(Local Function)  (0) 2022.05.29
[C#]멀티스레드(MultiThread)  (0) 2022.05.28
[C#]캡슐화(Encapsulation)  (0) 2022.05.25
[C#]확장 메서드(Extension Method)  (0) 2022.05.24
[C#]중첩 클래스(Nested Class)  (0) 2022.05.19

댓글