C#在其他线程上执行代码 [英] C# execute code on other thread

查看:93
本文介绍了C#在其他线程上执行代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在应用程序中的线程处理遇到了一些麻烦.我有一个多线程的客户端/服务器应用程序.我还在C#MonoDevelop for Unity3d中使用.不确定答案是否有任何不同.我将尝试解释我的问题所在:

I have some trouble with threading in my application. I have a multi-threaded client/server application. I'm also using C# MonoDevelop for Unity3d. Not sure if it makes any difference for the answer. I'll try to explain where my problem is:

Unity在单个线程上工作.因此,如果我想实例化一个使用统一类抽象类ScriptableObject的对象,则必须在运行Unity的主线程上完成此操作.

Unity works on a single thread. So if i want to instantiate an object which uses the abstract class ScriptableObject from unity, then this must be done on the main thread on which Unity runs.

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

But my server socket spawns a thread for every connected client, so that incoming data can be processed async. The received data is processed in the OnDataReceived() method (which runs on its own thread)

这里的问题是,我无法在OnDataReceived()线程内创建Player对象的实例.因为我的Player对象是从ScriptableObject继承的.这意味着该对象应在Unity主线程上创建.

The problem here is, is that i can't create an instance of a Player object inside the OnDataReceived() thread. Because my Player object inherits from ScriptableObject. Which means this object should be created on the main Unity thread.

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

But i have no idea how to do that... Is there a way to switch back to the main thread, so i can still create a Player object in the OnDataReceived() method?

推荐答案

.NET已经具有

.NET already has a concept of a SynchronizationContext, most often used for UI apps where thread affinity is required to invoke operations on UI controls (e.g. in WPF or WinForms). However, even outside a UI app, you can reuse these concepts for a general purpose thread-affinitized work queue.

此示例显示了如何使用WPF (来自WindowsBase.dll)在一个简单的控制台应用程序中,以及.NET 4.0任务类(

This sample shows how to use the WPF DispatcherSynchronizationContext (from WindowsBase.dll) in a simple console application, together with the .NET 4.0 task classes (TaskScheduler / Task) to invoke actions originating on child threads back on the main program thread.

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();
            }
        }
    }
}

示例输出:


Starting...
Saying hello from thread 3 (0) on thread 1.
Saying hello from thread 4 (0) on thread 1.
Saying hello from thread 3 (1) on thread 1.
Saying hello from thread 4 (1) on thread 1.
Saying hello from thread 3 (2) on thread 1.
Saying hello from thread 4 (2) on thread 1.
Saying hello from thread 3 (3) on thread 1.
Saying hello from thread 4 (3) on thread 1.
Saying hello from thread 3 (4) on thread 1.
Saying hello from thread 4 (4) on thread 1.
Shutdown.

这篇关于C#在其他线程上执行代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆