Server/Study

[Server] 멀티쓰레드

GiveZero 2023. 4. 25. 18:35

Thread

CPU 수행의 기본 단위

 

Task

스레드가 수행되는 환경

 

> 프로세스는 하나의 스레드가 있는 Task와 일치

 

스레드는 Thread ID, Program counter, Register set, Stack space로 구성

스레드는 자신의 레지스터 상태와 스택 을 지님

Code, Data 섹션이나 운영체제 자원들은 스레드끼리 공유

 

종류

 

싱글 스레드(Single thread)

하나의 스레드를 이용하여 한 번에 한 작업만 수행하는 것은

 

멀티 스레드(Multi thread)

한 프로세스가 여러 스레드로 동시에 여러 작업을 수행하는 것

 

장점

병렬성(Parallelism)

-  프로세스의 스레드들이 각각 다른 프로세서에서 병렬적으로 수행

 

동시성(Concurrency)

- 실제로는 각각의 시간에 한 작업만 수행되지만, 병렬적으로 수행되는 것처럼 보이는 것

 

응답성(Responsiveness)

-  작업을 분리해서 수행하므로 실시간으로 사용자에게 응답

자원 공유(Resource sharing)

- 프로세스는 오직 공유 메모리나 메시지 패싱을 이용해서 자원을 공유

- 스레드는 자신이 속한 프로세스 내의 스레드들과 메모리나 자원을 공유하여 효율적으로 사용

 

경제성(Economy)

- 프로세스를 새로 생성하는 비용보다 스레드를 새로 생성하는 게 훨씬 쌈

- Context switching의 오버헤드 또한 스레드가 더 경제적

 

확장성(Scalability)

- 멀티 스레드인 경우 한 프로세스를 여러 프로세서에서 수행할 수 있으므로 훨씬 효율적

 

쓰레드 생성 (C#)

using System;

namespace Server
{
    class Program
    {
        static void MainThread(object state)
        {
            while (true)
            {
                Console.WriteLine("Tread");
            }
        }
        
        static void Main(string[] args)
        {            
            Thread t = new Thread(MainThread);
            t.IsBackground = true; // true 일 경우 Main 이 끝날 때 Thread 도 종료
            t.Start();
            t.Join(); // 끝날 때 까지 Wait
            
            Console.WriteLine("Main");
    }
}

 

쓰레드 풀 사용 (C#)

using System;

namespace Server
{
    class Program
    {
        static void MainThread(object state)
        {
            while (true)
            {
                Console.WriteLine("Tread");
            }
        }
        
        static void Main(string[] args)
        {
            ThreadPool.QueueUserWorkItem(MainThread);
            
            Console.WriteLine("Main");
            while (true)
            {
                
            }
        }
    }
}

 

쓰레드 풀 먹통만들기 (5개의 쓰레드 모두 무한반복 작업)

using System;

namespace Server
{
    class Program
    {
        static void MainThread(object state)
        {
            while (true)
            {
                Console.WriteLine("Tread");
            }
        }
        
        static void Main(string[] args)
        {
            ThreadPool.SetMinThreads(1, 1);
            ThreadPool.SetMaxThreads(5, 5);

            // 무한반복
            for (int i = 0; i < 5; i++)
            {
                ThreadPool.QueueUserWorkItem((obj) => { while(true){} });
            }
            
            ThreadPool.QueueUserWorkItem(MainThread);
        }
    }
}

 

해결방안 - Task 사용

using System;

namespace Server
{
    class Program
    {
        static void MainThread(object state)
        {
            while (true)
            {
                Console.WriteLine("Tread");
            }
        }
        
        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)
                    {

                    }
                }, TaskCreationOptions.LongRunning);

                t.Start();
			}	
            // // 무한반복
            // for (int i = 0; i < 5; i++)
            // {
            //     ThreadPool.QueueUserWorkItem((obj) => { while(true){ } });
            // }
            
            ThreadPool.QueueUserWorkItem(MainThread);
        }
    }
}

오래 사용할 일을 Task를 이용하여 관리가능