2016-08-30 40 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