2016-08-30 60 views
2

首先,我使用統一。這使我堅持使用.NET 3.5。我目前正在使用一個服務器程序,該程序使用Socket對象的異步方法(例如,BeginReceiveBeginAcceptBeginReceiveFrom等)。當服務器從客戶端接收到數據包時,該數據包將在工作線程上接收。現在我在工作線程上留下了一些數據,並且我希望主線程使用我指定的函數處理這些數據。我實施了:FIFO編程的主線程調度程序?

using System; 
using System.Threading; 
using System.Collections; 
using System.Collections.Generic; 

public class MyDispatcherClass 
{ 
    public delegate void MyDel(); 
    private readonly Queue<MyDel> commands = new Queue<MyDel>(); 
    Object lockObj = new object(); 

    public void Add(MyDel dc) 
    { 
     lock (lockObj) 
     { 
      commands.Enqueue (dc); 
     } 
    } 

    public void Invoke() 
    { 
     lock (lockObj) 
     { 
      while (commands.Count > 0) 
      { 
       commands.Dequeue().Invoke(); 
      } 
     } 
    } 
} 

然後我就用這種方式:

// As a global variable: 
MyDispatcherClass SomeDispatcher = new MyDispatcherClass(); 

//The function that I want to call: 
public void MyFunction (byte[] data) 
{ 
    // Do some stuff on the main thread 
} 

//When I receive a message on a worker thread I do that: 
SomeDispatcher.Add (()=> MyFunction (byte[] data)); //Asuume that "data" is the message I received from a client 

//Each frame on the main thread I call: 
SomeDispatcher.Invoke(); 

經過一番研究,我發現lock聲明並不能保證100%實現FIFO。這不是我想要的,有時這可能會導致服務器出現故障!我希望以%100保證達到相同的結果,即數據將按照從客戶端收到的相同順序處理。我怎麼能做到這一點?

+0

你是否從一個客戶端獲得了所有的數據?如果是這樣,你可以添加一個'AddRange'方法到你的調度器,該調度器使用'IEnumerable '作爲參數,並將它們添加到同一個鎖體中。 – ArgusMagnus

+1

我以前檢查過這個。我從每個客戶端接收1到1的數據,並且我調用SomeDispatcher.Add的線程可能會不斷變化,即使對於每個客戶端(這是由Microsoft執行的)。 – None

回答

1

線程將以他們想要的任何順序運行,因此您無法強制訂單進入隊列。但是,您可以將更多數據放入隊列中,而不僅僅是最終將處理的內容。

如果向發送的數據添加DateTime(或者甚至只是一個具有指定順序的int),那麼當您從其中拉取數據時可以對該隊列進行排序(並且可能不會拉低小於0.5的任何數據秒)以給其他線程寫入其數據的時間。)

正常情況下,當處理客戶端 - 服務器關係時,每個線程代表一個客戶端,因此您不必擔心這個問題,因爲命令在線程內是FIFO,雖然它們可能不是當2個不同的客戶端發送消息時)。

您是否關閉並重新打開同一客戶端上的套接字?這可能會使它使用不同的線程。如果你需要一個特定的訂單,並且相互之間相當快地發送信息,那麼最好將套接字打開。

+1

「正常情況下,當處理客戶端 - 服務器關係時,每個線程代表一個客戶端」,錯誤。這是服務器的廉價實現。在c#中使用'Socket's的異步函數不會那樣做。 「你關閉並重新打開同一個客戶端上的套接字」,當然我不知道。 – None

+0

異步函數被設計爲在他們可以運行時運行,而不是按照您想要的順序運行。您可以切換到同步版本,還是將客戶端上的DateTime /處理訂單計數器添加爲您要發送的數據的一部分? –

+1

「你能切換到同步版本嗎?」:對性能產生巨大影響,並導致不可擴展的服務器,所以我根本不能。 「你可以在客戶端添加DateTime /處理訂單計數器作爲你發送的數據的一部分嗎?」:不幸的是,這是一個遊戲API。因此,我試圖減少發送的數據量可能的(我最多使用1個字節的UDP頭來解決套接字編程中的所有問題,管理所有連接,爲每個客戶端分配唯一的ID並進行連接握手),因此,如果我完全沮喪! – None