Files
Fishing2/Packages/cn.tuanjie.codely.bridge/Editor/Helpers/MainThreadHelper.cs
2026-03-09 17:50:20 +08:00

87 lines
3.0 KiB
C#

using System;
using System.Threading;
using System.Threading.Tasks;
using UnityEditor;
namespace UnityTcp.Editor.Helpers
{
/// <summary>
/// Helper class for main thread operations
/// </summary>
public static class MainThreadHelper
{
private static int mainThreadId;
/// <summary>
/// Initialize the main thread ID for safe thread checks
/// Call this from the main thread during static constructor
/// </summary>
public static void InitializeMainThreadId()
{
try { mainThreadId = Thread.CurrentThread.ManagedThreadId; } catch { mainThreadId = 0; }
}
/// <summary>
/// Invoke the given function on the Unity main thread and wait up to timeoutMs for the result.
/// Returns null on timeout or error; caller should provide a fallback error response.
/// </summary>
public static object InvokeOnMainThreadWithTimeout(Func<object> func, int timeoutMs)
{
if (func == null) return null;
try
{
// If mainThreadId is unknown, assume we're on main thread to avoid blocking the editor.
if (mainThreadId == 0)
{
try { return func(); }
catch (Exception ex) { throw new InvalidOperationException($"Main thread handler error: {ex.Message}", ex); }
}
// If we are already on the main thread, execute directly to avoid deadlocks
try
{
if (Thread.CurrentThread.ManagedThreadId == mainThreadId)
{
return func();
}
}
catch { }
object result = null;
Exception captured = null;
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
EditorApplication.delayCall += () =>
{
try
{
result = func();
}
catch (Exception ex)
{
captured = ex;
}
finally
{
try { tcs.TrySetResult(true); } catch { }
}
};
// Wait for completion with timeout (Editor thread will pump delayCall)
bool completed = tcs.Task.Wait(timeoutMs);
if (!completed)
{
return null; // timeout
}
if (captured != null)
{
throw new InvalidOperationException($"Main thread handler error: {captured.Message}", captured);
}
return result;
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to invoke on main thread: {ex.Message}", ex);
}
}
}
}