본문 바로가기

프로그램/유니티 C# 강좌

[유니티 C# 강좌] 23. 멀티스레드(Multi-thread)

728x90
반응형

멀티스레딩(Main Threading)은 여러 코어에서 한 번에 여러 개의 스레드를 처리하는 CPU 성능을 활용하는 프로그래밍의 한 유형입니다.

한 번에 하나가 아니라, 동시에 여러 개의 작업 또는 명령을 실행합니다.

 

어떤 스레드는 기본적으로 프로그램이 시작할 때 실행됩니다.

이 스레드가 바로 메인 스레드(Main Thread)입니다.

메인 스레드는 작업을 처리하기 위해 새로운 스레드를 생성합니다.

이러한 새 스레드는 다른 스레드와 병렬로 실행되며, 대개 실행이 완료되면 메인 스레드와 결과를 동기화합니다.

 

유니티에서 제공하는 많은 메서드들은 메인 스레드에서 실행되어야 합니다.

하지만, C#에서 제공하는 기능이나, 통신, 파일 로딩, 파싱 같은 것들은 멀티 스레드를 사용하면 됩니다.

 

1. 스레드 시작

 

네임 스페이스
using System.Threading;

 

1.1 스레드 생성

 

Thread 스레드변수명 = new Thread(스레드메서드명);

스레드변수명.Start()

...

스레드메서드

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {
        Thread thread = new Thread(Run);
        thread.Start();
    }

    void Run()
    {
        Debug.LogFormat("Thread#{0}: 시작", Thread.CurrentThread.ManagedThreadId);        
        Thread.Sleep(1000);
        Debug.LogFormat("Thread#{0}: 종료", Thread.CurrentThread.ManagedThreadId);
    }
}

 

Thread.Sleep(int millisecondsTimeout);는 스레드를 milliseconds 만큼 중지시킵니다.

 

1.2 ThreadStart 델리게이트 사용하여 스레드 생성

 

Thread 스레드변수명 = new Thread(new ThreadStart(스레드메서드명));

스레드변수명.Start()

...

스레드메서드

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {
        Thread thread = new Thread(new ThreadStart(Run));
        thread.Start();
    }

    void Run()
    {
        Debug.LogFormat("Thread#{0}: 시작", Thread.CurrentThread.ManagedThreadId);        
        Thread.Sleep(1000);
        Debug.LogFormat("Thread#{0}: 종료", Thread.CurrentThread.ManagedThreadId);
    }
}

 

1.3 람다식을 사용하여 스레드 생성

 

Thread 스레드변수명 = new Thread(() => 스레드메서드명());

스레드변수명.Start()

...

스레드메서드

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {                   
        Thread thread = new Thread(() => Run());
        thread.Start();
    }

    void Run()
    {
        Debug.LogFormat("Thread#{0}: 시작", Thread.CurrentThread.ManagedThreadId);        
        Thread.Sleep(1000);
        Debug.LogFormat("Thread#{0}: 종료", Thread.CurrentThread.ManagedThreadId);
    }
}

 

1.4 익명메서드를 이용한 스레드 생성

 

Thread 스레드변수명 = new Thread(delegate ()
{
    스레드메서드명();
});

스레드변수명.Start()

...

스레드메서드

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {
        Thread thread = new Thread(delegate ()
        {
            Run();
        });
        thread.Start();
    }

    void Run()
    {
        Debug.LogFormat("Thread#{0}: 시작", Thread.CurrentThread.ManagedThreadId);        
        Thread.Sleep(1000);
        Debug.LogFormat("Thread#{0}: 종료", Thread.CurrentThread.ManagedThreadId);
    }
}

 

1.5 간단한 표현으로 스레드 바로 실행하기

 

new Thread(() => 스레드메서드명()).Start();

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {
        new Thread(() => Run()).Start();
    }

    void Run()
    {
        Debug.LogFormat("Thread#{0}: 시작", Thread.CurrentThread.ManagedThreadId);        
        Thread.Sleep(1000);
        Debug.LogFormat("Thread#{0}: 종료", Thread.CurrentThread.ManagedThreadId);
    }
}

 

2. 스레드 매개변수 전달

 

2.1 매개변수가 1개인 경우

 

매개변수가 1개이면, 스레드 생성 할 때는 매개변수를 넣어 주지 않고, Start 메서드를 사용할 때 넣어 주면 됩니다.

 

Thread 스레드변수명 = new Thread(스레드메서드명);

스레드변수명.Start(매개변수)

...

스레드메서드(Object obj)

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {       
        Thread thread = new Thread(Run);
        thread.Start(1);
    }

    static void Run(object obj)
    {
        Debug.Log(obj);
    }
}

 

2.2 매개변수가 2개 이상인 경우

 

매개변수가 2개 이상이면, ThreadStart에서 파라미터 전달하면 됩니다.

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {
        Thread thread = new Thread(() => Sum(1, 2, 3));
        thread.Start();
    }

    static void Sum(int d1, int d2, int d3)
    {
        int sum = d1 + d2 + d3;
        Debug.Log(sum);
    }
}

 

3. 백그라운드 스레드

 

일반적으로 스레드는 포그라운드(Foreground)에서 실행됩니다.

만약, 스레드를 백그라운드(Background)로 실행하고 싶으면, Start()를 실행하기 전에 IsBackground 속성을 true로 지정하면 됩니다.

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {
        Thread thread = new Thread(new ThreadStart(Run));
        thread.IsBackground = true;
        thread.Start();
    }

    static void Run()
    {       
        Debug.Log("Run");
    }
}

 

4. 스레드 대기

 

4.1 Join 메서드

 

메인 스레드에서 서브 스레드를 실행시키고, 서브 스레드가 실행되는 동안 메인 스레드를 블락시켜 스레드를 대기 시키는 방법으로 Join 메서드를 사용합니다.

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {
        Thread thread = new Thread(Run);
        thread.Start(); 

        for (int i = 0; i < 3; i++) 
        {
            Debug.LogFormat($"메인 스레드 : {i}");
            Thread.Sleep(100); 
        }

        thread.Join();
        Debug.Log("메인 스레드 종료");
    }

    static void Run()
    {
        for (int i = 0; i < 5; i++) 
        {
            Debug.LogFormat($"서브 스레드 : {i}");
            Thread.Sleep(100); 
        }
        Debug.Log("서브 스레드 종료");
    }
}

 

4.2 EventWaitHandle 클래스 사용

 

EventWaitHandle 클래스의 WaitOne 메서드와 Set 메서드를 사용하여스레드를 블락시킵니다.

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {
        EventWaitHandle eventWaitHandle 
            = new EventWaitHandle(false, EventResetMode.ManualReset); 

        Thread thread = new Thread(Run);
        thread.Start(eventWaitHandle);
        Debug.Log("서브 스레드 시작");

        for (int i = 0; i < 1; i++)
        {
            Debug.LogFormat($"메인 스레드 : {i}");
            Thread.Sleep(100);
        }

        eventWaitHandle.WaitOne();
        Debug.Log("메인 스레드 종료");
    }

    static void Run(object obj)
    {
        EventWaitHandle eventWaitHandle = obj as EventWaitHandle;

        for (int i = 0; i < 2; i++) 
        {
            Debug.LogFormat($"서브 스레드 : {i}");
            Thread.Sleep(100); 
        }

        Debug.Log("서브 스레드 종료");
        eventWaitHandle.Set();
    }
}

 

5. 스레드 폴링

 

스레드 메서드는 하나를 만든 뒤, 재사용이 가능한데 이를 스레드 폴링이라 합니다.

스레드 폴링은 ThreadPool클래스의 QueueUserWorkItem메서드를 사용하면 됩니다.

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {
        ThreadPool.QueueUserWorkItem(Run); // 출력 : null
        ThreadPool.QueueUserWorkItem(Run, 1); // 출력 : 1
        ThreadPool.QueueUserWorkItem(Run, 2); // 출력 : 2
    }

    static void Run(object obj)
    {     
        Debug.Log(obj);
    }
}

 

6. 스레드 강제 종료

 

서버 스레드가 실행 중에 메인 스레드에서 강제로 종료하고 싶으면, Abort 메서드를 사용하면 됩니다.

 

using UnityEngine;
using System.Threading;

public class ThreadDemo : MonoBehaviour
{
    void Start()
    {
        Thread thread = new Thread(Run);
        thread.Start();

        for (int i = 0; i < 3; i++)
        {
            Debug.LogFormat($"메인 스레드 : {i}");
            Thread.Sleep(100);
        }

        thread.Abort();
        Debug.Log("메인 스레드 종료");
    }

    static void Run()
    {
        for (int i = 0; i < 5; i++)
        {
            Debug.LogFormat($"서브 스레드 : {i}");
            Thread.Sleep(100);
        }
    }
}
728x90
반응형