在特定线程中运行代码

时间:2013-11-14 12:16:24

标签: c# multithreading

我有一个与外部库通信的控制台应用程序。不幸的是,所有对库的调用都必须来自同一个线程。

如何将方法调用从一个线程发送到另一个线程? (显然,将方法结果发送回调用线程。)

(不,这与GUI编程无关。不,使用GUI消息泵不起作用。)

我真正想要的是,特定类的每个方法总是在同一个线程中执行。但我不知道该怎么做。

1 个答案:

答案 0 :(得分:1)

我的建议是执行Windows Forms和WPF设置单线程消息泵的操作 - 继承SynchronizationContexthttp://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext%28v=vs.110%29.aspx

在您的实现中,您将需要维护一个线程安全的消息队列,类似于这个: http://www.codeproject.com/Articles/56369/Thread-safe-priority-queue-in-C 您的消息泵工作线程将不断检查新代理,并调用它们。

那么为什么不写一个消息泵?

好吧,通过继承SynchronizationContext,您可以免费获得所有CLR好东西,例如BackgroundWorkerAsyncOperationManager和新的await/async模式关键字!他们将神奇地加入你的图书馆主题。

以下是基本消息泵的一些代码。它实现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);
            }
        }
    }
}