Home [멀티쓰레드] 쓰레드 생성
Post
Cancel

[멀티쓰레드] 쓰레드 생성

Thread 생성

C#에서 Thread 생성하는 방법은 간단하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
static void thread1()
{
    while(true)
        Console.WriteLine("Hello Thread!");
}

static void Main(string[] args) // 메인 쓰레드
{
    Thread t = new Thread(thread1); // 쓰레드 생성 및 작업(함수) 넘기기
    t.Start(); // 쓰레드 시작

    Console.WriteLine("Hello World!");
}
1
2
3
4
5
Hello World!
Hello Thread!
Hello Thread!
Hello Thread!
...

프로그램에서는 기본적으로 메인 쓰레드가 있고 위 코드에서는 쓰레드를 하나 더 생성해서 수행하는 것을 보여주고 있다.
또한 메인 쓰레드는 종료하더라도 다른 쓰레드가 남아있으면 프로그램이 종료되지 않는 것을 볼 수 있다. (background에서 실행시킬 경우 메인 쓰레드가 종료되면 프로그램도 종료된다.)

쓰레드를 생성할 때 여러 설정도 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static void thread1()
{
    for(int i = 0; i < 5; i++)
        Console.WriteLine("Hello Thread!");
}

static void Main(string[] args)
{
    Thread t = new Thread(thread1); // 쓰레드 생성 및 작업 넘기기
    t.Name = "Test Thread"; // 쓰레드 이름 지정(디버깅할때 확인해볼 수 있다)
    t.IsBackground = true; // background에서 실행되도록 설정할 수 있다(기본 설정은 false)
    t.Start(); // 쓰레드 시작

    Console.WriteLine("Waiting for Thread!");

    t.Join(); // 쓰레드가 종료될때까지 기다린다.

    Console.WriteLine("Hello World!");
}
1
2
3
4
5
6
7
Waiting for Thread!
Hello Thread!
Hello Thread!
Hello Thread!
Hello Thread!
Hello Thread!
Hello World!

필요할 때 매번 쓰레드를 생성해서 관리해도 되긴 하지만 사실 쓰레드를 생성하는 것은 큰 부담이 되는 작업이다. 그렇기에 매번 쓰레드를 생성하지 않고 이전에 생성했던 것을 재사용하는 방법으로 ThreadPool을 활용해 볼 수 있다.

ThreadPool

ThreadPool은 쓰레드가 생성되고 작업을 끝낸 후에 사라지지 않고 Queue에 대기하고 있다가 또 작업이 들어왔을 때 그 작업을 들고가서 수행한다.
쓰레드를 매번 생성하고 지우는 것이 아니라 이미 생성해 놓은 쓰레드를 활용하는 것이기에 부담을 좀 줄일 수 있다. 또한 쓰레드 개수를 제한할 수 있기 때문에 쓰레드가 무한히 막 생성되는 것을 방지할 수 있다. 다만 오래걸리는 작업들을 수행시켰을 경우 쓰레드를 오랫동안 붙잡게 되어 쓰레드 부족으로 다른 작업들을 못하게 될 수도 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static void thread1(object state)
{
    for(int i = 0; i < 5; i++)
        Console.WriteLine("Hello Thread!");
}

static void Main(string[] args)
{
    ThreadPool.SetMinThreads(1, 1); // 쓰레드 최소 개수 1
    ThreadPool.SetMaxThreads(5, 5); // 쓰레드 최대 개수 5

    for (int i = 0; i < 5; i++)
        ThreadPool.QueueUserWorkItem((obj) => { while(true){ } }); // 람다식을 이용해 일부러 끝나지 않는 작업을 넘김

    ThreadPool.QueueUserWorkItem(thread1); // 쓰레드 부족으로 실행이 안됨
}

오래 걸리는 작업일 경우 ThreadPool에서 쓰레드를 사용하지 않고 따로 생성해서 관리하는 것이 효율적일 수 있다.
사실 이러한 점들을 효율적으로 관리할 수 있는 방법으로 Task가 있다.

Task

Thread와 사용법이 비슷하며 기본적으로 ThreadPool에서 쓰레드를 가져와 작업을 수행한다. 다만 오래 걸릴 것같은 작업은 따로 생성해서 관리할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static void thread1(object state)
{
    for(int i = 0; i < 5; i++)
        Console.WriteLine("Hello Thread!");
}

static void Main(string[] args)
{
    ThreadPool.SetMinThreads(1, 1);
    ThreadPool.SetMaxThreads(5, 5);

    for (int i = 0; i < 5; i++)
    {
        // Task도 ThreadPool에서 쓰레드를 가져오지만
        // 오래걸릴 것같은 작업은 이렇게 따로 지정해놓으면 Task에서 따로 관리한다.
        Task t = new Task(() => { while (true) { } }, TaskCreationOptions.LongRunning);
        t.Start();
    }

    ThreadPool.QueueUserWorkItem(thread1); // 실행되는 것을 볼 수 있다.

    while (true) { } // 메인쓰레드가 종료되지 않도록
}
1
2
3
4
5
Hello Thread!
Hello Thread!
Hello Thread!
Hello Thread!
Hello Thread!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void thread1(object state)
{
    for(int i = 0; i < 5; i++)
        Console.WriteLine("Hello Thread!");
}

static void Main(string[] args)
{
    ThreadPool.SetMinThreads(1, 1);
    ThreadPool.SetMaxThreads(5, 5);

    for (int i = 0; i < 5; i++)
    {
        Task t = new Task(() => { while (true) { } });
        t.Start();
    }

    ThreadPool.QueueUserWorkItem(thread1); // 실행되지 않는다

    while (true) { } // 메인쓰레드가 종료되지 않도록
}

C#에서 보통 쓰레드를 직접생성해서 관리할 일는 거의 없고 ThreadPool 개념과 Task만 잘 사용해도 충분하다.

This post is licensed under CC BY 4.0 by the author.