Win32匿名管道在首次读取后损坏

时间:2015-03-10 11:03:14

标签: c winapi ipc broken-pipe

我正在通过win32 api创建一个进程并阅读它的stdout和err。 问题是在第一次成功阅读ReadFile()之后,我总是得到管道中剩余数据的下一个管道错误(109)。 (所以我只在第一次调用时读取与缓冲区一样大的内容) 我怀疑它可能是因为我同时阅读了管道,但在孩子终止后?

void read_pipes(std::string &output, HANDLE read_pipe) {
        assert(read_pipe != nullptr && read_pipe != INVALID_HANDLE_VALUE);
        char buffer[4096];
        DWORD bytes_left_to_read, err_code; int i = 0;
        do {
            memset(&buffer, 0, 4096);
            err_code = 0;
            if (!ReadFile(read_pipe, buffer, 4096 - 1, &bytes_left_to_read, NULL)) {
                err_code = GetLastError();
            }
            assert(err_code != ERROR_IO_PENDING);
            if (err_code != 0 && err_code != ERROR_MORE_DATA) {
                char sys_err_msg[128];
                sys_err_msg[128 - 1] = '\0';
                FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, err_code, MAKELANGID(0x09, 0x01), sys_err_msg, 127, nullptr);
                std::cerr << "Failed to read failed mmdb_importer log, because " << sys_err_msg << ";" << err_code
                        << std::endl;
                break;
            }
            output.append(buffer);
        } while (true);

调用read的部分代码(在http://pastebin.com/vakLULyf下完整)

if (WaitForSingleObject(mddb_importer_info.hProcess, 60000) == WAIT_TIMEOUT) {
        //Kill the importer, probably hangs
        TerminateProcess(mddb_importer_info.hProcess, EXIT_FAILURE);
    }
    GetExitCodeProcess(mddb_importer_info.hProcess, &mddb_importer_return);
    //assert (mddb_importer_return != STILL_ACTIVE);

    switch (mddb_importer_return) {
        case EXIT_SUCCESS:
            file_to_upload.uploaded = true;
            break;
        default:
            assert(file_to_upload.uploaded == false);
        {
            read_pipes(std::ref(file_to_upload.log), mddb_importer_stderr_r);
            std::clog << "MDDB_Importer failed with err: : " << file_to_upload.log << std::endl;
            read_pipes(std::ref(file_to_upload.log), mddb_importer_stdout_r);
            std::clog << "And total size of log " << file_to_upload.log.length() << std::endl;
        }
            break;
    }

1 个答案:

答案 0 :(得分:0)

是的,我看起来订单错了,但由于我不想在一个可能悬挂的过程中永远等待,我现在通过线程读取管道我在等待之前启动我的read_pipes函数使用超时,使用std :: async。 以Snipett为例:

    if (!CloseHandle(mddb_importer_stderr_w)) throw std::runtime_error("Can not create mddb_importer pipes");


auto err = std::async(std::launch::async, read_pipes, mddb_importer_stderr_r);
auto out = std::async(std::launch::async, read_pipes, mddb_importer_stdout_r);

if (WaitForSingleObject(mddb_importer_info.hProcess, 60000) == WAIT_TIMEOUT) {
    //Kill the importer, probably hangs
    TerminateProcess(mddb_importer_info.hProcess, EXIT_FAILURE);
}
GetExitCodeProcess(mddb_importer_info.hProcess, &mddb_importer_return);
//assert (mddb_importer_return != STILL_ACTIVE);

const std::string err_string = err.get();