【问题标题】:How to debug "Cannot close an uninitialised Msg" FaultException?如何调试“无法关闭未初始化的消息”FaultException?
【发布时间】:2017-07-26 10:20:05
【问题描述】:

我的应用程序因“无法关闭未初始化的消息”未处理异常而崩溃。这可能是由于从多个线程访问套接字。

我在调试这个问题时遇到问题,因为当我查看我的代码时,所有对套接字的访问都是在轮询线程中完成的——直接在 ReceiveReady 事件处理程序中(根据我的理解,它在轮询线程上运行)或在手动创建 Task (new Task(...)) 然后在轮询线程 (task.Start(poller)) 上启动。 所以我看不到可能发生这种情况的地方。

第二个问题是未处理的异常——我将所有发送/接收都包装在 try-catch 中,但异常发生在外面的某个地方。

我正在寻找如何有效地调试它并找出我的代码中行为不端的地方。


代码示例——正如我所写的,我只使用了两个“模式”:

直接使用 poller 线程(感谢 poller 线程上触发的事件):

 private async void OnMessageReceiveReady(object sender, NetMQSocketEventArgs args)
 {
     NetMQSocket socket = args.Socket;

     NetMQMessage mq_msg = socket.ReceiveMultipartMessage();
     ...

从任意线程切换到poller的线程:

Task sending = new Task(() =>
{
    foreach (NetMQFrame address in mq_envelope)
        socket.SendMoreFrame(address.ConvertToString());

    socket.SendFrame(response_data);
});
sending.Start(this.sharedPoller);
await sending.ConfigureAwait(false);

【问题讨论】:

  • 你能给我们展示一些相关的代码吗(尽可能多)?
  • 代码是否锁定在您读取/写入接收数据的位置? ReceiveReady 事件处理程序应该很少处理数据。它应该读取数据并放入缓冲区并继续。缓冲区的处理应该在不同的线程或主代码中处理。
  • @mjwills,我更新了问题——我多次使用此代码,仅此而已。
  • @jdweng,你的意思是像lock 命令?不,事件是在 poller 的线程上触发的,所以在给定的时间可能只有一个在运行,对吗?感谢您的提示,但它涉及性能问题,而不是多线程执行。是否有可能因为ReceiveReady 代码需要更多时间而得到这样的异常?
  • TCP 数据报的最大大小约为 1500 字节。您可以获得零字节的数据报(保持活动消息),数据报可以拆分为小数据报并由路由器和服务器组合。所以发送的数据并不总是会被接收到。所以接收解析器必须足够聪明才能处理部分消息。我的 ReceiveReady 方法我只是将需要的数据添加到 List 对象。然后有一个解析器然后删除一个一次从 List.Ascii 数据中读取消息,我的解析器将从 List 读取,直到找到第一个返回。然后删除锁定代码中的行,因此 RxReady 被锁定。

标签: c# multithreading sockets debugging netmq


【解决方案1】:

不幸的是,除了反复试验和更多日志记录之外,我没有找到任何其他方法。

问题在于处理套接字——我正在运行 poller(共享)并尝试使用 RemoveDispose 套接字,但我发现这两种方法是异步的。

作为解决方案,我将RemoveDispose 组合在单独的任务中,然后安排它在轮询器中运行。有了task,我可以在上面调用Wait,这样我就可以在Dispose 中实现阻塞、同步行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-16
    • 2012-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    • 2021-05-17
    相关资源
    最近更新 更多