繁体   English   中英

如何取消 PIPE 操作?

[英]How do I cancel a PIPE operation?

我有一个 C++ 和 C# 应用程序,我在其中使用命名管道相互发送命令。 它运行良好,直到我注意到我无法取消Read()调用,我使用了一个停止变量,但没有注意到这不是我需要的全部,因为它无法读取停止变量状态直到下车Read()调用。 我发现我会在CreateNamedPipe()调用中使用PIPE_NOWAIT属性。 当我添加它时,C# 抛出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_LISTENINGConnectNamedPipe()调用之后,发生在我添加PIPE_NOWAIT 为什么是那个错误? 我该如何解决? 这是添加支持以取消命名管道操作的正确方法吗? 我会杀死正在运行Listen()读,但我读到它不是一个好的实践(它甚至不起作用)。

注意:我正在处理现有的代码库,由于时间原因,我希望避免使用NamedPipeClientStream重写所有内容。

在 C++ 中,您需要使用重叠的 io 创建文件,然后WaitForMultipleObjects(..., INFINITE); 对于停止事件和 IO。

如果你得到停止事件,那么你CancelIO(); .

对于 C# msdn : Overlapped允许您创建重叠对象(读取所需)。

stackoverflow : pinvoke ReadFile 这显示了如何使用重叠选项本机调用 ReadFile。

stackoverflow : waitformultipleobjects 功能解释了如何调用 WaitForMultipleObjects。

在解决这类问题时,我创建了一个独立的函数

ReadFileWithEvent( HANDLE file, VOID * pData, size_t data, HANDLE exitEvent, BOOL & signalled );

它打包创建了一个重叠的对象,等待并向调用者解释停止发生,并且读取尚未完成。 这简化了我需要的代码。

我解决了这个与PeekNamedPipe (),我得到的数量总字节可用,并调用ReadFile (),只有当它> 0。这是一个简单的方法来模拟非阻塞模式,我可以退出只设置一个线程中运行循环donetrue

像这样的东西:

   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, ...)) {
             // ...
           }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM