简体   繁体   English

在特定线程中运行代码

[英]Run code in a specific thread

I have a console application which talks to an external library. 我有一个与外部库对话的控制台应用程序。 Unfortunately all calls to the library must be made from the same thread. 不幸的是,对库的所有调用必须从同一线程进行。

How can I send method calls from one thread to another? 如何将方法调用从一个线程发送到另一个线程? (And, obviously, send the method results back to the calling thread.) (并且,显然,将方法结果发送回调用线程。)

(No, this isn't to do with GUI programming. No, using the GUI message pump won't work.) (不,这与GUI编程无关。不,使用GUI消息泵将不起作用。)

What I really want is for every single method on a particular class to always be executed in the same thread. 我真正想要的是使特定类上的每个方法始终在同一线程中执行。 But I have no idea how to do that. 但是我不知道该怎么做。

My advice is to do what Windows Forms and WPF do to set up their single threaded message pumps - inherit SynchronizationContext . 我的建议是执行Windows Forms和WPF的操作以设置其单线程消息泵-继承SynchronizationContext http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext%28v=vs.110%29.aspx http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext%28v=vs.110%29.aspx

In your implementation, you will need to maintain a thread safe message queue, similar to this one: http://www.codeproject.com/Articles/56369/Thread-safe-priority-queue-in-C Your message pump worker thread will constantly check for new delegates, and invoke them. 在您的实现中,您将需要维护一个类似于以下内容的线程安全消息队列: http : //www.codeproject.com/Articles/56369/Thread-safe-priority-queue-in-C您的消息泵工作线程将不断检查新的委托,并调用它们。

So why not just write a message pump? 那么,为什么不只写一个消息泵呢?

Well, by inheriting SynchronizationContext , you get all the CLR goodies like BackgroundWorker , AsyncOperationManager and the new await/async pattern keyword for free! 好吧,通过继承SynchronizationContext ,您可以免费获得所有CLR好东西,例如BackgroundWorkerAsyncOperationManager和新的await/async模式关键字! They will all magically join back to your library thread. 他们都将神奇地加入您的库线程中。

Here is some code for a basic message pump. 这是基本消息泵的一些代码。 It does not implement SynchronizationContext : 没有实现SynchronizationContext

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace MessagePump
{
    class Program
    {
        static void Main(string[] args)
        {
            MessagePump p = new MessagePump();
            p.Start();
            p.AddMessage(() => Console.WriteLine("message 1"));
            p.AddMessage(() => Console.WriteLine("message 2"));
            p.AddMessage(() => Console.WriteLine("message 3"));

            Console.ReadLine();
            p.Stop();
        }
    }

    class MessagePump
    {
        bool m_Working = false;
        Queue<Action> m_Actions = new Queue<Action>();

        public void Start()
        {
            m_Working = true;
            Thread t = new Thread(DoPump);
            t.Name = "Message Pump Thread";
            t.Start();
        }
        void DoPump()
        {
            while (m_Working)
            {
                try
                {
                    Monitor.Enter(m_Actions);
                    while (m_Actions.Count > 0)
                    {
                        m_Actions.Dequeue()(); //dequeue and invoke a delegate
                    }
                }
                finally
                {
                    Monitor.Exit(m_Actions);
                }

                Thread.Sleep(100); //dont want to lock this core!
            }
        }
        public void Stop()
        {
            m_Working = false;
        }

        public void AddMessage(Action act)
        {
            lock (m_Actions)
            {
                m_Actions.Enqueue(act);
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM