개요

  • Unity는 Thread를 생성하여 사용할 수 있다.
  • 다만 이 영역에서는 MonoBehaviour가 동작하지 않는다.
  • 따라서 멀티 쓰레딩(multi-threading) 환경에서는, Unity의 ManagedThread를 체크할 필요가 있다.

방법

  • 아래 예제에서는 ManagedThread에서 동작하기 원하는 Action을 RunOnUiThread에 넣는다.
  • EditorApplication.Update를 사용하여 Main Application의 업데이트를 감지한다.
  • 이 방식을 사용하면, StartCoroutine 같은 명령을 외부 Thread에서 입력할 수 있다.
    • 실제 실행은 ManagedThread에서 된다.

코드

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;

public class FileBasketSyncContext
{
    private static SynchronizationContext context;
    private static TaskScheduler taskScheduler;
    private static int managedThreadId;
    private static Queue<Action> runInUpdate = new Queue<Action>();

    public static bool isUiThread => managedThreadId == Thread.CurrentThread.ManagedThreadId;

    public void Awake()
    {
        context = SynchronizationContext.Current;
        managedThreadId = Thread.CurrentThread.ManagedThreadId;
        taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();

        EditorApplication.update += OnEditorApplicationUpdate;
    }

    public static SynchronizationContext GetContext()
    {
        return context;
    }

    public static void RunOnUiThread(Action runnable)
    {
        if (managedThreadId == Thread.CurrentThread.ManagedThreadId)
        {
            runnable();
        }
        else
        {
            lock (runInUpdate)
            {
                runInUpdate.Enqueue(runnable);
            }
        }
    }

    private static void OnEditorApplicationUpdate()
    {
        while (runInUpdate.Count > 0)
        {
            Action runnable = null;
            lock (runInUpdate)
            {
                if (runInUpdate.Count > 0)
                {
                    runnable = runInUpdate.Dequeue();
                }
            }
            // runnable이 null이 아니라면 실행
            runnable?.Invoke();
        }
    }
}

+ Recent posts