WaitNamedPipe的重叠I / O替代方法是什么?

时间:2012-03-26 19:40:49

标签: c++ c windows named-pipes

WaitNamedPipe函数允许管道客户端应用程序同步等待命名管道服务器上的可用连接。然后,您调用CreateFile以作为客户端打开管道。伪代码:

// loop works around race condition with WaitNamedPipe and CreateFile
HANDLE hPipe;
while (true) {
    if (WaitNamedPipe says connection is ready) {
        hPipe = CreateFile(...);
        if (hPipe ok or last error is NOT pipe busy) {
            break; // hPipe is valid or last error is set
        }
    } else {
        break; // WaitNamedPipe failed
    }
}

问题是这些都是阻塞的同步调用。异步执行此操作的好方法是什么?例如,我似乎无法找到使用重叠I / O执行此操作的API。例如,对于管道服务器ConnectNamedPipe函数提供lpOverlapped参数,允许服务器异步等待客户端。然后管道服务器可以调用WaitForMultipleObjects并等待I / O操作完成,或等待发出任何其他事件(例如,一个事件通知线程取消挂起的I / O并终止)。

我能想到的唯一方法是在一个有短暂有限超时的循环中调用WaitNamedPipe,如果超时则检查其他信号。或者,在循环调用CreateFile中,检查其他信号,然后使用短暂延迟(或Sleep)调用WaitNamedPipe。例如:

HANDLE hPipe;
while (true) {
    hPipe = CreateFile(...);
    if (hPipe not valid and pipe is busy) {
        // sleep 100 milliseconds; alternatively, call WaitNamedPipe with timeout
        Sleep(100);
        // TODO: check other signals here to see if we should abort I/O
    } else
        break;
}

但在我看来,这种方法对高天堂很不利。如果管道暂时不可用,则线程继续运行 - 使用电源吸收CPU,需要将内存页保留在RAM中等等。在我看来,一个依赖Sleep或短暂超时的线程表现不佳,是多线程编程草率的标志。

但在这种情况下,替代方案是什么?

3 个答案:

答案 0 :(得分:5)

WaitNamedPipe完全没用,如果指定超时并且没有服务器等待它,它将只使用所有cpu。

只需使用CreateFile一遍又一遍地调用Sleep,然后根据需要将其移至其他线程。没有API替代方案。

唯一的“好处”WaitNamedPipe提供的是,如果您想知道是否可以连接到命名管道但是您明确不想实际打开连接。这是垃圾。

如果你真的想彻底,你唯一的选择是

  • 确保打开命名管道的任何程序始终在连接命名管道后立即再次调用CreateNamedPipe
  • 让您的程序实际检查该程序是否正在运行。
  • 如果你的意图真的没有额外的联系,仍然打电话给CreateNamedPipe,当有人连接时,告诉他们离开,直到他们等待一段时间,关闭管道。

答案 1 :(得分:2)

为什么服务器不能只创建更多管道?如果情况很少,那么您描述的场景中的性能损失不是问题。

即。如果通常有足够的管道可以使用CreateFile/Sleep代替WaitForMultipleObjects那么重要吗?性能打击无关紧要。

我还要质疑客户端中重叠IO的必要性。一次与多少台服务器进行通信?如果答案小于10,那么你可以合理地为每个连接创建一个线程。

基本上我说我认为没有重叠WaitforNamedPipe的原因是因为没有合理的用例需要它。

答案 2 :(得分:0)

您可以在 if(!empty($_POST['sortBy'])){ $orderSQL = " ORDER BY id ".$_POST['sortBy']; }else{ $orderSQL = " ORDER BY id DESC"; } $query = $connect->query("SELECT * FROM products $orderSQL"); 打开管道文件系统,然后使用\\.\pipe\发送FSCTL_PIPE_WAIT