2013-11-14 141 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