私はC++パイプサーバーアプリケーションとWindowsの名前付きパイプ(デュプレックス、メッセージモード、別の読み取りスレッドでの待機/ブロック)を介して通信するC#パイプクライアントアプリケーションを持っています。特定の書き込みで二重の名前付きパイプがハングする
フォーム 'textchanged'イベントに応答して、クライアントからパイプへの書き込みを試みるまで、すべてがうまく動作します(パイプ経由でデータを送受信しています)。これを行うと、クライアントはパイプ書き込み呼び出し(またはautoflushがオフの場合はフラッシュ)でハングします。サーバのアプリケーションに侵入すると、パイプのReadFileコールを待っていて、戻ってこないことも明らかです。 私は別のスレッドでクライアントの書き込みを実行しようとしました - 同じ結果。
デッドロックや競合状態の疑いがありますが、どこに...私がパイプに同時に書き込んでいるとは思わないのか分かりません。
Update1:メッセージモードではなくバイトモードでパイプを試しました。同じロックアップです。
Update2:奇妙なことに、サーバーからクライアントに大量のデータを送ってきたら、ロックアップを癒すことができます。
Serverコード:
DWORD ReadMsg(char* aBuff, int aBuffLen, int& aBytesRead)
{
DWORD byteCount;
if (ReadFile(mPipe, aBuff, aBuffLen, &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, &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 && bytesRead>0)
mMsgCallback(rxBuff, bytesRead, mCallbackContext);
}
else
{
mClientConnected = false;
}
}
Close();
Sleep(1000);
}
return 0;
}
クライアントコード:
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>0 && !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();
}
}
サーバー側での読み取りエラーの処理は、少しばかげているようです。診断手段として、一時的にサーバーを変更して、読み取りエラーが発生した場合に終了し、クライアント側の書き込みとサーバー側の読み取りが同じパイプに関連していることを確認することをお勧めします。 –
クライアントをシングルスレッド化できるように、パイプをパイプに書き込まないようにサーバーを変更して状況を単純化すると便利です。これで問題が解消されない場合は、スレッドの問題ではないことを少なくとも確認することができます。 –
Chris:コードを追加しました:) @Harry:それはエラーを返さずにReadFile fnに頑丈に座っています。複数のパイプを提案しています...下記を参照してください。サーバーの書き込みを試みませんでした:同じ結果。まだ見ています... -/ – MGB