BinaryFormatter.反序列化挂起整个线程

本文关键字:线程 挂起 反序列化 BinaryFormatter | 更新日期: 2023-09-27 17:53:34

我有两个通过命名管道连接的简单应用程序。在客户端,我有一个方法,每n毫秒检查传入消息:

private void timer_Elapsed(Object sender, ElapsedEventArgs e)
{
      IFormatter f = new BinaryFormatter();
      try
      {
           object temp = f.Deserialize(pipeClient); //hangs here
           result = (Func<T>)temp;
      }
      catch
      {
      }
}

一开始管道是空的,f.Deserialize方法挂起整个应用程序。我都不能检查水管有没有空吗?这个问题有什么解决办法吗?

UPD:尝试XmlSerializer,一切都是一样的

BinaryFormatter.反序列化挂起整个线程

让你挂心的是pipeClient.Read(调用,这两个格式化程序都在内部进行。

当您调用Read时,这是Stream的预期行为:


类型:System.Int32
读入缓冲区的字节总数。这可能小于字节数如果该字节数当前不可用,则请求,如果为0到达流的结尾。

所以流将阻塞直到数据显示,或者抛出一个超时异常,如果它是支持超时的流类型。它永远不会在没有读取任何内容的情况下返回,除非你"在流的末尾",这对于PipeStream(或类似的NetworkStream)只发生在连接关闭时。

解决这个问题的方法是不要使用计时器来检查是否有新消息到达,只需启动一个后台线程并让它处于循环中,它会阻塞自己,直到消息显示。

class YourClass
{
    public YourClass(PipeStream pipeClient)
    {
        _pipeClient = pipeClient;
        var task = new Task(MessageHandler, TaskCreationOptions.LongRunning);
        task.Start();
    }
    //SNIP...
    private void MessageHandler()
    {
        while(_pipeClient.IsConnected)
        {
            IFormatter f = new BinaryFormatter();
            try
            {
                 object temp = f.Deserialize(_pipeClient);
                 result = (Func<T>)temp;
            }
            catch
            {
                //You really should do some kind of logging.
            }
        }
    }
}