C#在其他线程上执行代码

我的应用程序中的线程有问题。 我有一个multithreading客户端/服务器应用程序。 我也在为Unity3d使用C#MonoDevelop。 不确定答案是否有任何不同。 我会尝试解释我的问题所在:

Unity适用于单个线程。 因此,如果我想实例化一个使用Unity的抽象类ScriptableObject的对象,那么必须在Unity运行的主线程上完成。

但是我的服务器套接字为每个连接的客户端生成一个线程,因此可以将传入的数据处理为异步。 接收到的数据在OnDataReceived()方法中处理(在自己的线程上运行)

这里的问题是,我无法在OnDataReceived()线程内创建一个Player对象的实例。 因为我的Player对象inheritance自ScriptableObject 。 这意味着应该在主Unity线程上创建此对象。

但我不知道怎么做…有没有办法切换回主线程,所以我仍然可以在OnDataReceived()方法中创建一个Player对象?

.NET已经有了SynchronizationContext的概念,最常用于UI应用程序,其中需要线程相关性来调用UI控件上的操作(例如,在WPF或WinForms中)。 但是,即使在UI应用程序之外,您也可以将这些概念重用于通用线程关联工作队列。

此示例演示如何在简单的控制台应用程序中使用WPF DispatcherSynchronizationContext (来自WindowsBase.dll ),以及.NET 4.0任务类( TaskScheduler / Task ),以在主程序线程上调用源自子线程的操作。

 using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Threading; internal sealed class Program { private static void Main(string[] args) { int threadCount = 2; using (ThreadData data = new ThreadData(threadCount)) { Thread[] threads = new Thread[threadCount]; for (int i = 0; i < threadCount; ++i) { threads[i] = new Thread(DoOperations); } foreach (Thread thread in threads) { thread.Start(data); } Console.WriteLine("Starting..."); // Start and wait here while all work is dispatched. data.RunDispatcher(); } // Dispatcher has exited. Console.WriteLine("Shutdown."); } private static void DoOperations(object objData) { ThreadData data = (ThreadData)objData; try { // Start scheduling operations from child thread. for (int i = 0; i < 5; ++i) { int t = Thread.CurrentThread.ManagedThreadId; int n = i; data.ExecuteTask(() => SayHello(t, n)); } } finally { // Child thread is done. data.OnThreadCompleted(); } } private static void SayHello(int requestingThreadId, int operationNumber) { Console.WriteLine( "Saying hello from thread {0} ({1}) on thread {2}.", requestingThreadId, operationNumber, Thread.CurrentThread.ManagedThreadId); } private sealed class ThreadData : IDisposable { private readonly Dispatcher dispatcher; private readonly TaskScheduler scheduler; private readonly TaskFactory factory; private readonly CountdownEvent countdownEvent; // In this example, we initialize the countdown event with the total number // of child threads so that we know when all threads are finished scheduling // work. public ThreadData(int threadCount) { this.dispatcher = Dispatcher.CurrentDispatcher; SynchronizationContext context = new DispatcherSynchronizationContext(this.dispatcher); SynchronizationContext.SetSynchronizationContext(context); this.scheduler = TaskScheduler.FromCurrentSynchronizationContext(); this.factory = new TaskFactory(this.scheduler); this.countdownEvent = new CountdownEvent(threadCount); } // This method should be called by a child thread when it wants to invoke // an operation back on the main dispatcher thread. This will block until // the method is done executing. public void ExecuteTask(Action action) { Task task = this.factory.StartNew(action); task.Wait(); } // This method should be called by threads when they are done // scheduling work. public void OnThreadCompleted() { bool allThreadsFinished = this.countdownEvent.Signal(); if (allThreadsFinished) { this.dispatcher.InvokeShutdown(); } } // This method should be called by the main thread so that it will begin // processing the work scheduled by child threads. It will return when // the dispatcher is shutdown. public void RunDispatcher() { Dispatcher.Run(); } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } // Dispose all IDisposable resources. private void Dispose(bool disposing) { if (disposing) { this.countdownEvent.Dispose(); } } } } 

样本输出:

开始...
在线程1上从线程3(0)说你好。
在线程1上从线程4(0)说你好。
在线程1上从线程3(1)说你好。
在线程1上从线程4(1)说你好。
在线程1上从线程3(2)说你好。
在线程1上从线程4(2)说你好。
在线程1上从线程3(3)说你好。
在线程1上从线程4(3)说你好。
在线程1上从线程3(4)说你好。
在线程1上从线程4(4)说你好。
关掉。

您可以通过诸如的类与原始线程进行通信

 class Communicator { public static volatile bool CreatePlayer; } 

在套接字代码中,更改CreatePlayer变量。 在接收器代码中,检查变量并创建一个播放器。 之后,将CreatePlayer设置为false。 与其他事物相似。 注意在两个线程上同时操作一个变量 – 例如,为CreatePlayer设置四个布线可能比使用int NumPlayersToCreate更好,这样两个线程都不会尝试不断访问相同的数据。 当然,你必须剖析并看到。 最后一件事:确保两个线程中更改的变量都标记为volatile。 这使得每个线程都从主内存访问数据而不是将其保留在缓存中(否则,每个线程都不会注意到在另一个线程的缓存中更改的数据)。

是的,这不是最高效或最优雅的解决方案,但它是最简单的。 我相信有人会建议更多的东西; 如果你愿意,我也可以这样做。 但是,你似乎不熟悉multithreading,所以我认为你想要一些简单易用的东西。