2013-11-14 109 views
1

我有一个与外部库进行通信的控制台应用程序。不幸的是,所有对库的调用都必须使用相同的线程。在特定线程中运行代码

如何将方法调用从一个线程发送到另一个线程? (而且,很明显,发送方法的结果返回给调用线程。)

(不,这不是GUI编程做。不,使用GUI消息泵将无法正常工作。)

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

+3

在静态构造函数创建一个线程,并保持它活着的等待。所有的作业(调用公共类的方法)都是“排队”,然后这个线程会逐个完成它们,然后再等待。 – Sinatr

+0

你如何期望另一个线程接收“通知”?我想,它一定是在听他们到达 - 手动检查一些入站队列。你已经提到过,这不像GUI编程,所以你只是没有一些胜利形式,它会调用你的回调,所以你不能应用IncomingFunctionCall_OnArrived之类的东西 - 你仍然应该检查你的通知拥有。 – Agat

+0

你的库绑定到你初始化它的线程(类似于一个UI),还是只需要序列化访问? – Gusdor

回答

1

我的建议是做Windows窗体和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好吃的东西,如BackgroundWorker,AsyncOperationManager和新的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); 
      } 
     } 
    } 
} 
+1

搞清楚如何创建一个线程安全的队列确实是我遇到的问题,一旦你有了这个问题,这只是一个排队lambda函数的问题,代表你想完成的工作 – MathematicalOrchid

+0

@MathematicalOrchid我编了一个代码示例。 – Gusdor