2010-01-18 47 views
1

我在寫一個c#組件,只會在我的公司內部使用。該組件封裝與特定桌面應用程序需要與之通信的多個服務器的通信。服務器可以將未經請求的消息發送到組件,這些組件在單獨的線程中被「捕獲」。如何在不阻塞並等待的情況下通知另一個線程上的某條消息的主線程?

我希望這個組件的大部分在其創建線程的上下文中執行。我不希望單獨的消息線程做任何消息處理。相反,我想通知主線程有一條等待處理的消息。想要在創建線程的上下文中執行的原因是庫的用戶可能不知道多線程,並且我希望能夠在可能的情況下同步所有操作。

有沒有一種簡單的方式發信號通知正在運行的線程?主線程將進行各種常量處理,並且消息線程將不斷旋轉等待消息。值得注意的是,消息線程被封裝在第三方庫中。一旦收到消息,它就會執行回調。我想回調做一些像mainthread.notify(消息)。

編輯: 對不起,我不太清楚我想讓主線程做什麼。我不希望主線程立即處理消息線程發送的消息。我希望它在不久的將來能夠處理消息(如WinForms消息循環的工作方式)。

編輯2:

場景:

Console App created on Thread1 
Thread2 created, which spins listening for Messages 
Console App runs as normal 
Message arrives on Thread2 
Thread2 fires event MessageReady(sender, message) 
Thread2 continues spinning 
At the earliest convenience, Thread1 processes the message from MessageReady 

我已經做了一些閱讀,似乎編組代碼到另一個線程是一個相當困難的態度,我懷疑是同步這個過程將是值得的。

+0

我得到了你沒有使用WCF的感覺。我建議你這樣做。 – 2010-01-18 01:27:42

+0

不,我沒有使用WCF。發送/檢索到服務器的消息是許可的,並且提供庫以與它們一起工作。我不認爲WCF可以幫助我。 – 2010-01-18 02:07:37

回答

1

不,這是不可能的。線程必須先閒置,然後才能向其中注入代碼。這是通過,例如,Control.BeginInvoke(Windows窗體)或Dispatcher.BeginInvoke(WPF)完成的。這些UI庫通常需要在UI線程上執行代碼,以便它們對UI線程進行封送處理的顯式支持。

線程處於「空閒」狀態很重要。如果.NET支持某種異步注入方法,你將會有可怕的重入問題。

+0

您提到的Control.BeginInvoke示例正是我在類庫中所掌握的內容。該組件的主線程並不總是執行,理論上可以是WinForms應用程序的GUI線程。像Windows消息泵一樣是理想的。 – 2010-01-18 01:16:28

+0

檢查我的答案在這個線程:http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/09b7285d-3294-483c-ad92-36d202285d43 – 2010-01-18 01:19:10

+0

我已經標記了這個答案是正確的,雖然我不打算創建GUI控件來允許跨線程編組。 – 2010-01-18 05:27:14

0

由於您可能不希望線程放棄當前正在執行的操作,因此您需要某種線程才能看到的任務隊列 - 這不必比任何更先進隊列,其中T是您用來表示每個任務的某種類型。維護一個隊列並在那裏添加消息,這樣線程就可以在他們完成當前正在做的事情時處理它們。

使用信號量讓您的工作線程在隊列爲空時等待新數據,並在該信號量上脈衝,如果您將新消息添加到空隊列。這可以防止他們在不斷輪詢隊列時浪費CPU週期。

如果你想要幾個工作線程,你所需要做的就是確保每個線程都有自己的隊列,並且你將完全控制哪個線程運行什麼。

編輯:在再次閱讀這個問題時,我不確定你的問題是你真的需要線程立即做一些工作。如果是這樣的話,我看不出這是可能的,因爲你不能隨意的注入代碼 - 你很可能會破壞當時正在執行的任何代碼。

+0

正確,我希望主線程能夠在不久的將來在某個時刻處理消息。 – 2010-01-18 02:16:14

+0

它可能有助於確切知道線程在您要「注入」消息的位置應該做什麼。也許你可以通過使用優先級隊列使其工作,所以如果在那裏發生了大量工作,那麼在任何等待「空閒」任務之前處理傳入消息? – 2010-01-18 02:20:58

1

如果您的組件將是一個Windows窗體上,那麼這裏是一個途徑實現自己的目標:

在組件代碼:

public event EventHandler MessageReceived; 

private void UnsolicitedMessageReceived(...) 
{ 
    if (MessageReceived != null) 
    { 
    // this will invoke on UI thread 
    Parent.Invoke(MessageReceived, this, EventArgs.Empty); 
    } 
} 

在你的表格,你可能有:

MyCoolComponent1.MessageReceived += new EventHandler(MessageReceived); 

private void MessageReceived(object sender, EventArgs e) 
{ 
    // do some stuff here 
} 
+0

這是假設庫將用於WinForm。儘管這是最可能的情況,但並不能保證。 – 2010-01-18 03:00:19

0

一種選擇是將代理從主線程傳遞到可用作回調的子線程,以表示他們有消息。子線程可以通過回調傳遞消息,該消息將消息保存在基於內存的集合或持久性存儲中,並且主線程在適當的時候檢查該消息。

你可以更進一步,並且不要讓子線程根本指示主線程,而是讓子線程將消息寫入數據庫,並讓主線程在方便時檢查數據庫。你甚至可以使用數據庫(通過事務)來處理併發。如果系統崩潰,這樣做的好處是不會丟失消息。甚至可以讓您跨服務器傳播子線程(或主線程)。

相關問題