如何取消PIPE操作?

时间:2015-10-21 18:23:43

标签: c# c++ windows multithreading named-pipes

我有一个C ++和C#应用程序,我使用命名管道向其他人发送命令。它一直运作良好,直到我注意到我无法取消Read()电话,我使用了一个停止变量,但没有注意到这不是我所需要的,因为它无法解决问题。 t读取停止变量状态,直到Read()调用。我发现我会在PIPE_NOWAIT调用中使用CreateNamedPipe()属性。当我添加它时,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);

所以我的问题是ConnectNamedPipe()调用后错误为ERROR_PIPE_LISTENING,在我添加PIPE_NOWAIT后发生。为什么会出错?我该如何解决?这是添加支持以取消命名管道操作的正确方法吗?我会杀死Listen()正在运行的地方,但我认为它不是一个很好的实践(它甚至无法工作)。

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

2 个答案:

答案 0 :(得分:1)

在C ++中,您需要创建具有重叠io的文件,然后var hasAtLeastOneFalseStatus = _.any($scope.inspectionReviews, function (value, key) { return !value.IsNormal; }) $scope.status = hasAtLeastOneFalseStatus ? false: true; 创建一个停止事件和IO。

如果您收到停止事件,则为WaitForMultipleObjects(..., INFINITE);

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

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

stackoverflow : waitformultipleobjects functionality解释如何调用WaitForMultipleObjects。

解决这类问题时,我创建了一个独立的功能

CancelIO();

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

答案 1 :(得分:0)

我用PeekNamedPipe()解决了这个问题,我得到了可用字节总数,并且仅当它是&#39}时才调用ReadFile()。 0.这是一种模拟非阻塞模式的简单方法,我可以退出在线程内运行的循环,只需将done设置为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, ...)) {
             // ...
           }
}