簡體   English   中英

Windows:如何讓子進程在不關閉輸入匿名管道的情況下讀取它?

[英]Windows: how can I let the child process read the input anonymous pipe without closing it?

根據主題,我正在嘗試開發一個簡單的管道式父/子程序。 該程序的主要目的是使子進程保持活動狀態,並使用std::cinstd::cout在父/子進程之間進行通信。

在Linux上,所有這些工作都很好。

在Windows上,我一直按照這里的示例進行操作,與Linux有一個獨特的區別:一個必須調用

CloseHandle(g_hChildStd_IN_Wr)

寫入子管道並沖洗它。 這具有關閉管道的副作用,從而終止了我與子進程的連接
我也嘗試過使用FlushFileBuffers,但是它不起作用。

知道如何在不關閉匿名管道的情況下刷新緩沖區嗎?

以下是父級子級進程的來源。
如果進程的代碼基本上是上面示例中的代碼:

// IN_Wr_ is initialized as below with bInheritHandle=TRUE
::CreatePipe(&IN_Rd_, &IN_Wr_, &saAttr, 0);
// and
::SetHandleInformation(IN_Wr_, HANDLE_FLAG_INHERIT, 0)
// When I spawn the child process I do
STARTUPINFO         siStartInfo = {0};
siStartInfo.cb = sizeof(STARTUPINFO); 
siStartInfo.hStdError = INVALID_HANDLE_VALUE;
siStartInfo.hStdOutput = OUT_Wr_;
siStartInfo.hStdInput = IN_Rd_;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
...
// then in order to write to std::cin
const DWORD reqSz = static_cast<DWORD>(std::strlen(request));
DWORD       written = 0;
while(true) {
    DWORD   curWritten = 0;
    if(!WriteFile(IN_Wr_, request + written, reqSz-written, &curWritten, NULL))
        throw std::runtime_error("Error on WriteFile");
    written += curWritten;
    if(written == reqSz) {
        // all written, done
        break;
    }
}
::FlushFileBuffers(IN_Wr_);
// only when I do this CloseHandle then the child process
// is able to read data
::CloseHandle(IN_Wr_);

代碼是一個簡單的回顯服務器,大致如下:

buif[2048+1];
while(std::cin) {
    std::cin.read(buf, 2048);
    const auto  rb = std::cin.gcount();
    buf[rb] = '\0';
    std::cout << buf << std::endl; // this does flush
}

這是您的問題:

std::cin.read(buf, 2048);

它確實在執行您要求的操作:等待它讀取2048個字符或到達文件末尾。 您不會發送2048個字符,因此直到服務器關閉管道(在此上下文中該管道算作文件結尾)之前,什么都不會發生。

相反,您應該使用類似getline(s, 2048, '\\0') ,當看到空字符時它將停止讀取。 (當然,您將需要修改發送者,以便它在字符串末尾寫入該空字符。)

或者,您可以使用本機API: ReadFile具有您似乎想要的語義。 理想情況下,您將使用消息模式管道,該管道是專門為此類使用而設計的。

此處的文章可能會有所幫助: https : //support.microsoft.com/zh-cn/kb/190351 它有一節介紹了使用printf將數據發送到重定向的管道時的刷新問題,這似乎是在您的情況下完成的。 建議的解決方案是使用fflush(NULL)刷新C運行時IO緩沖區。

看來問題是std::cin::read的MSFT實現(甚至是fread(..., ..., ..., stdin) )。 如果不是依靠:

// C++ API
while(std::cin) {
    std::cin.read(buf, 2048);
    ...
// or also "C" API
int rb = 0;
while(0 < (rb = fread(buf, 2048, 1, stdin))) {
    ...

我做

// Low level Win32 "C" API
while(::ReadFile(hStdin, buf, 2048, &rb, 0)) {
    ...
// or also low level unix-like "C" API
int rb = 0;
while(0 < (rb = _read(0, buf, 2048))) {
    ...

上面的示例工作正常(很有趣,甚至不需要調用FlushFileBuffers )。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM