c#:同步网络通信时出现死锁

时间:2013-06-28 18:00:13

标签: c# multithreading networking synchronization deadlock

我想在c#中开发一个满足以下要求的网络库:

  • 在两个方向上为多个请求使用相同的连接
  • 提供一个简单的包装方法,如response = Connection.Send(message);
  • 支持SSL(这就是我不使用SocketAsyncEventArgs的原因)。

基本上我有两个主题:

  • 第一个线程侦听(同步)传入消息并调度所有内容
  • 第二个线程负责请求处理

所以基本上代码如下(非常简短):

BlockingCollection _receivingQueue;
ConcurrentDictionary <MessageID, ResponseHandlerDelegate> _responseHandlers;
Dictionary <MessageID, Message> _responses;

void ListeningThread()
{
     while(true)
     {
          Message = ReadNetworkStream();
          _receivingQueue.Add(Message);
     }
}

void ProcessingThread()
{
      if(Message == Request)
            Dispatch(message);
      if(Message == ResponseForARequest)
      {
            _responses.Add(Message.ID, Message);
            _responseHandlers[Message.ID](Message);
      }

}

这似乎很有效。

然而,由于这是一个“易于使用”的库,我想开发上述功能:Response = Connection.Send(Message)

基本上我认为我可以使用ManuelResetEvent进行通知,当新响应到达时:

Dictionary <Guid, ManualResetEvents> _resetters;

Message Send(Message)
{
     ManualResetEvent mre = new ManuelResetEvent(false);
     _resetters.Add(Message.ID, mre);

     Connection.Send(Message);

     WaitFor(mre);

     return _responses[Message.ID];
}

MRE是从已注册的ResponseHandlerDelegate

设置的
ResponseArrived(Message)
{
     _responses.Add(Message.ID, Message);
     _resetters[Message.ID].Set();
}

只要没有并发双向通信,这就可以工作。由于服务器端和客户端都使用相同的代码,因此它们都在等待设置MRE ......

请注意,上面的所有内容都是某种伪代码,因为真正的类太长了。如果您需要特定的代码部分,请告诉我。

那么我的问题是什么?

我认为我制作的是一团糟。有没有一种简单的方法来解决这个问题?或者有人可以提供一个如何以不同方式实现这一点的想法吗?

我不想使用WCF,更好地控制较低层 - 主要是 - 因为我想自己开发它: - )

由于

1 个答案:

答案 0 :(得分:1)

为了在等待同步发送的响应时防止阻塞或死锁,您需要发送线程PER请求。否则发送B可以等待A的响应,A可以等待B的响应,也不会做任何事情(死锁),因为WaitFor是一个同步锁,它阻止调用你的Send方法的线程实际接收任何东西。

将其视为状态机,机器A和B运行您的库:

A --> send to B
B --> send to A
A --> wait for response
B --> wait for response
A --> receive message from B, but still waiting for B's response
B --> receive message from A, but still waiting for A's response

结果:

A --> has message from B but can't stop waiting to process it
B --> has message from A but can't stop waiting to process it

简而言之:您需要超过2个线程。您需要N个线程,其中N是您要同时执行的请求数,即使所有这些线程共享一个连接。使用内置或自制的线程池可以帮助您重用线程并降低垃圾收集成本。

可以根据请求启动一个帖子......事实上,它是鼓励的。当单个线程也等待响应时,单个线程无法充分处理多个请求。但是,如果你不等待回应,那将是另一回事。