如何取消 PIPE 操作?
How do I cancel a PIPE operation?
我有一个 C++ 和 C# 应用程序,我在其中使用命名管道向彼此发送命令。它运行良好,直到我注意到我无法取消 Read()
call, I was using a stop variable but didn't notice this wasn't all I need because it couldn't read the stop variable state until get off the Read()
call. I found I would use PIPE_NOWAIT attribute in the CreateNamedPipe()
call. When I added it the C# throw an System.NullReferenceException 因为 FileStream
为空,它是从 new FileStream(clientHandle, FileAccess.ReadWrite, BUFFER_SIZE, true);
创建的,其中 clientHandle
的创建如下:
private void Listen()
{
while (!exitLoop)
{
clientHandle = CreateNamedPipe(this.pipeName,
DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_NOWAIT,
255,
BUFFER_SIZE,
BUFFER_SIZE,
0,
IntPtr.Zero);
if (clientHandle.IsInvalid)
{
return;
}
int ok = ConnectNamedPipe(clientHandle, IntPtr.Zero);
//could not connect client
if (ok == 0) // here's the error, getLastError() = ERROR_PIPE_LISTENING
{
return;
}
stream = new FileStream(clientHandle, FileAccess.ReadWrite, BUFFER_SIZE, true);
// ....
}
如果重要的话,在 C++ 中管道是这样创建的:
hPipe1 = CreateFile(lpszPipename1,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (!IsValidPipe(hPipe1))
{
openError();
return;
}
hPipe2 = CreateFile(lpszPipename2,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
所以我的问题是:错误是 ERROR_PIPE_LISTENING
在 ConnectNamedPipe()
调用之后,发生在我添加 PIPE_NOWAIT
之后。为什么会出现这个错误?我该如何解决?这是添加支持以取消命名管道操作的正确方法吗?我会杀死 Listen()
在 运行 中的 theread,但我读到它不是一个好的实践(它甚至都不起作用)。
注意:我正在处理现有的代码库,出于时间原因,我想避免使用 NamedPipeClientStream
重写所有内容。
在 C++ 中,您需要创建具有重叠 io 的文件,然后 WaitForMultipleObjects(..., INFINITE);
用于停止事件和 IO。
如果你得到停止事件,那么你CancelIO();
。
对于 C# msdn : Overlapped 允许您创建重叠对象(读取所需)。
Whosebug : pinvoke ReadFile。这显示了如何使用重叠选项本地调用 ReadFile。
Whosebug : waitformultipleobjects functionality 解释如何调用 WaitForMultipleObjects。
在解决这类问题时我创建了一个独立的函数
ReadFileWithEvent( HANDLE file, VOID * pData, size_t data, HANDLE exitEvent, BOOL & signalled );
打包创建重叠对象,等待并向调用者解释停止已发生,读取尚未完成。这简化了我需要的代码。
我用 PeekNamedPipe
(), I get the number total of bytes available and call ReadFile
() 解决了这个问题,只有当它 > 0 时。这是模拟非阻塞模式的简单方法,我可以在线程内退出循环 运行,只需设置 [=13] =] 到 true
.
像这样:
while(!done) {
DWORD total_available_bytes = 0;
if(!PeekNamedPipe(hPipe2, NULL, 0, NULL, &total_available_bytes, NULL)) {
/* error handling goes here */
break;
}
// for avoid overuse of the CPU, sleep for a while until next check.
if(total_available_bytes == 0) {
Sleep(500);
continue;
}
if(ReadFile(hPipe2, ...)) {
// ...
}
}
我有一个 C++ 和 C# 应用程序,我在其中使用命名管道向彼此发送命令。它运行良好,直到我注意到我无法取消 Read()
call, I was using a stop variable but didn't notice this wasn't all I need because it couldn't read the stop variable state until get off the Read()
call. I found I would use PIPE_NOWAIT attribute in the CreateNamedPipe()
call. When I added it the C# throw an System.NullReferenceException 因为 FileStream
为空,它是从 new FileStream(clientHandle, FileAccess.ReadWrite, BUFFER_SIZE, true);
创建的,其中 clientHandle
的创建如下:
private void Listen()
{
while (!exitLoop)
{
clientHandle = CreateNamedPipe(this.pipeName,
DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_NOWAIT,
255,
BUFFER_SIZE,
BUFFER_SIZE,
0,
IntPtr.Zero);
if (clientHandle.IsInvalid)
{
return;
}
int ok = ConnectNamedPipe(clientHandle, IntPtr.Zero);
//could not connect client
if (ok == 0) // here's the error, getLastError() = ERROR_PIPE_LISTENING
{
return;
}
stream = new FileStream(clientHandle, FileAccess.ReadWrite, BUFFER_SIZE, true);
// ....
}
如果重要的话,在 C++ 中管道是这样创建的:
hPipe1 = CreateFile(lpszPipename1,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (!IsValidPipe(hPipe1))
{
openError();
return;
}
hPipe2 = CreateFile(lpszPipename2,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
所以我的问题是:错误是 ERROR_PIPE_LISTENING
在 ConnectNamedPipe()
调用之后,发生在我添加 PIPE_NOWAIT
之后。为什么会出现这个错误?我该如何解决?这是添加支持以取消命名管道操作的正确方法吗?我会杀死 Listen()
在 运行 中的 theread,但我读到它不是一个好的实践(它甚至都不起作用)。
注意:我正在处理现有的代码库,出于时间原因,我想避免使用 NamedPipeClientStream
重写所有内容。
在 C++ 中,您需要创建具有重叠 io 的文件,然后 WaitForMultipleObjects(..., INFINITE);
用于停止事件和 IO。
如果你得到停止事件,那么你CancelIO();
。
对于 C# msdn : Overlapped 允许您创建重叠对象(读取所需)。
Whosebug : pinvoke ReadFile。这显示了如何使用重叠选项本地调用 ReadFile。
Whosebug : waitformultipleobjects functionality 解释如何调用 WaitForMultipleObjects。
在解决这类问题时我创建了一个独立的函数
ReadFileWithEvent( HANDLE file, VOID * pData, size_t data, HANDLE exitEvent, BOOL & signalled );
打包创建重叠对象,等待并向调用者解释停止已发生,读取尚未完成。这简化了我需要的代码。
我用 PeekNamedPipe
(), I get the number total of bytes available and call ReadFile
() 解决了这个问题,只有当它 > 0 时。这是模拟非阻塞模式的简单方法,我可以在线程内退出循环 运行,只需设置 [=13] =] 到 true
.
像这样:
while(!done) {
DWORD total_available_bytes = 0;
if(!PeekNamedPipe(hPipe2, NULL, 0, NULL, &total_available_bytes, NULL)) {
/* error handling goes here */
break;
}
// for avoid overuse of the CPU, sleep for a while until next check.
if(total_available_bytes == 0) {
Sleep(500);
continue;
}
if(ReadFile(hPipe2, ...)) {
// ...
}
}