title: Duplex named pipe hangs on a certain write
body: <p>I have a C++ pipe server app and a C# pipe client app communicating via Windows named pipe (duplex, message mode, wait/blocking in separate read thread).</p>
  
  <p>It all works fine (both sending and receiving data via the pipe) until I try and write to the pipe from the client in response to a forms 'textchanged' event.  When I do this, the client hangs on the pipe write call (or flush call if autoflush is off).  Breaking into the server app reveals it's also waiting on the pipe ReadFile call and not returning.
  I tried running the client write on another thread -- same result.</p>
  
  <p>Suspect some sort of deadlock or race condition but can't see where... don't think I'm writing to the pipe simultaneously.</p>
  
  <p>Update1: tried pipes in byte mode instead of message mode - same lockup.</p>
  
  <p>Update2: Strangely, if (and only if) I pump lots of data from the server to the client, it cures the lockup!?</p>
  
  <p>Server code:</p>
  
  <pre><code>DWORD ReadMsg(char* aBuff, int aBuffLen, int&amp; aBytesRead)
  {
      DWORD byteCount;
      if (ReadFile(mPipe, aBuff, aBuffLen, &amp;byteCount, NULL))
      {
          aBytesRead = (int)byteCount;
          aBuff[byteCount] = 0;
          return ERROR_SUCCESS;
      }
  
      return GetLastError();  
  }
  
  DWORD SendMsg(const char* aBuff, unsigned int aBuffLen)
  {
      DWORD byteCount;
      if (WriteFile(mPipe, aBuff, aBuffLen, &amp;byteCount, NULL))
      {
          return ERROR_SUCCESS;
      }
  
      mClientConnected = false;
      return GetLastError();  
  }
  
  DWORD CommsThread()
  {
      while (1)
      {
          std::string fullPipeName = std::string("\\\\.\\pipe\\") + mPipeName;
          mPipe = CreateNamedPipeA(fullPipeName.c_str(),
                                  PIPE_ACCESS_DUPLEX,
                                  PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
                                  PIPE_UNLIMITED_INSTANCES,
                                  KTxBuffSize, // output buffer size
                                  KRxBuffSize, // input buffer size
                                  5000, // client time-out ms
                                  NULL); // no security attribute 
  
          if (mPipe == INVALID_HANDLE_VALUE)
              return 1;
  
          mClientConnected = ConnectNamedPipe(mPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
          if (!mClientConnected)
              return 1;
  
          char rxBuff[KRxBuffSize+1];
          DWORD error=0;
          while (mClientConnected)
          {
              Sleep(1);
  
              int bytesRead = 0;
              error = ReadMsg(rxBuff, KRxBuffSize, bytesRead);
              if (error == ERROR_SUCCESS)
              {
                  rxBuff[bytesRead] = 0;  // terminate string.
                  if (mMsgCallback &amp;&amp; bytesRead&gt;0)
                      mMsgCallback(rxBuff, bytesRead, mCallbackContext);
              }
              else
              {
                  mClientConnected = false;
              }
          }
  
          Close();
          Sleep(1000);
      }
  
      return 0;
  }
  </code></pre>
  
  <p>client code:</p>
  
  <pre><code>public void Start(string aPipeName)
  {
      mPipeName = aPipeName;
  
      mPipeStream = new NamedPipeClientStream(".", mPipeName, PipeDirection.InOut, PipeOptions.None);
  
      Console.Write("Attempting to connect to pipe...");
      mPipeStream.Connect();
      Console.WriteLine("Connected to pipe '{0}' ({1} server instances open)", mPipeName, mPipeStream.NumberOfServerInstances);
  
      mPipeStream.ReadMode = PipeTransmissionMode.Message;
      mPipeWriter = new StreamWriter(mPipeStream);
      mPipeWriter.AutoFlush = true;
  
      mReadThread = new Thread(new ThreadStart(ReadThread));
      mReadThread.IsBackground = true;
      mReadThread.Start();
  
      if (mConnectionEventCallback != null)
      {
          mConnectionEventCallback(true);
      }
  }
  
  private void ReadThread()
  {
      byte[] buffer = new byte[1024 * 400];
  
      while (true)
      {
          int len = 0;
          do
          {
              len += mPipeStream.Read(buffer, len, buffer.Length);
          } while (len&gt;0 &amp;&amp; !mPipeStream.IsMessageComplete);
  
          if (len==0)
          {
              OnPipeBroken();
              return;
          }
  
          if (mMessageCallback != null)
          {
              mMessageCallback(buffer, len);
          }
  
          Thread.Sleep(1);
      }
  }
  
  public void Write(string aMsg)
  {
      try
      {
          mPipeWriter.Write(aMsg);
          mPipeWriter.Flush();
      }
      catch (Exception)
      {
          OnPipeBroken();
      }
  }
  </code></pre>