C#学习笔记(3) 中断被NamedPipeServer.WaitForConnection()或NamedPipeClientStream.Connect()阻塞的线程

NamedPipeServer.WaitForConnection()函数的行为真的是很霸道,这个函数工作在阻塞模式,而且是不可中断的,也就是说,一旦调用了服务端管道流对象的这个函数,只要没有客户端与之连接,调用线程就会被一只阻塞下去,没有任何办法可以直接中断这个阻塞!要想从这种阻塞中脱离出来,唯一的办法就是在调用线程中创建一个NamedPipeClientStream对象,然后与这个阻塞了线程的NamedPipeServerStream对象建立连接,这样就从阻塞状态脱离出来了。

同样,NamedPipeClientStream.Connect()函数也一样的霸道,在完成与服务端的连接之前,没有任何手段可以直接中断掉该操作,调用线程会被一只阻塞。解决的方法也是在调用线程中创建一个服务端管道流,建立自内部的管道流连接,使得NamedPipeClientStream对象跳出Connect()状态,这样调用线程就可以被中断了。

以下是使用了服务端管道流的线程的代码片段:

   class ServerThread
   {
      public ServerThread(string pipeName)
      {
         this.pipeName = pipeName;
         this.pipedStream = new NamedPipeServerStream(pipeName);
      }

      public void run()
      {
         Console.WriteLine(">> SERVER_THREAD: waiting for client connection ...");
         pipedStream.WaitForConnection();
         Console.WriteLine("  done.");

         // 其他操作 ... ...

         if (pipedStream != null)
         {
            shutdownPipedStream();
         }
      }

      public void stop()
      {
         if (!pipedStream.IsConnected)
         {
            connectSelf();    // 建立自我链接,以使得服务端管道流跳出WaitForConnection()。
            shutdownPipedStream();
         }
      }

      private void shutdownPipedStream()
      {
         pipedStream.Close();
         pipedStream.Dispose();
         pipedStream = null;
      }

      private void connectSelf() // 这个函数用于中断处于WaitForConnection状态的服务端管道流。
                                 // NamedPipeServerStream.WaitForConnection会一直处于阻塞状态直至与客户端管道流建立连接,
                                 // 这个阻塞状态无法被中断!
      {
         NamedPipeClientStream npcs = new NamedPipeClientStream(pipeName);
         npcs.Connect();
      }

      private String pipeName;
      private NamedPipeServerStream pipedStream;
   }

以下是主线程代码片段,创建ServerThread对象,并调用其stop方法中断,使得其跳出WaitForConnection状态。

   class MultiThreadExchange
   {
      public void run()
      {
         Console.Write("creating thread ...");
         ServerThread serverThreadInstance = new ServerThread(pipeName);
         Thread serverThread = new Thread(new ThreadStart(serverThreadInstance.run));
         serverThread.Start();
         Console.WriteLine("  done.");

         Console.WriteLine("sleeping ...");
         Thread.Sleep(waitTime);
         Console.WriteLine("  wake up.");
         
         Console.Write("stopping thread ...");
         serverThreadInstance.stop();
         Console.WriteLine("  done.");
      }

      private const string pipeName = "testPipe";
      private const int waitTime = 3000;
   }

运行结果如下:

creating thread ...  done.
>> SERVER_THREAD: waiting for client connection ...
sleeping ...
  wake up.
stopping thread ...  done.
  done.
System.NullReferenceException: 未将对象引用设置到对象的实例。
   在 LearnCSharpConsole.ServerThread.run() 位置 F:\LJF\program\VCS\WinForm\LearnCSharpGUI\LearnCSharpConsole\MultiThreadExchange.cs:行号 55

中断NamedPipeClientStream.Connect()的代码示例如下:

   class ClientThread
   {
      public ClientThread(string pipeName)
      {
         this.pipeName = pipeName;
         this.pipedStream = new NamedPipeClientStream(pipeName);
      }

      public void run()
      {
         Console.Write(">> CLIENT_THREAD: connecting to server pipe stream ...");
         pipedStream.Connect();
         Console.WriteLine("  done.");

         // other processing ...

         if (pipedStream != null)
         {
            stop();
         }
      }

      public void stop()
      {
         if (!pipedStream.IsConnected)
         {
            connectSelf();
         }
         pipedStream.Close();
         pipedStream.Dispose();
         pipedStream = null;
      }

      private void connectSelf()
      {
         NamedPipeServerStream npss = new NamedPipeServerStream(pipeName);
         npss.WaitForConnection();
      }

      private String pipeName;
      private NamedPipeClientStream pipedStream;
   }

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值