等待Windows上的进程随机失败

时间:2016-03-23 21:05:56

标签: c++ windows

我有一个编译器项目。我有一个集成测试套件用于我的编译器,它将示例源编译成一个对象,调用ld来链接它,然后调用可执行文件并检查结果。这三个步骤中的每一个都是与测试驱动程序分开的新过程。

不幸的是我看到随机测试失败,因为出于某种原因,当我来链接时,先前的测试还没有完成运行,即使我在开始下一步之前明确等待每个进程的终止。因此ld失败,因为它无法写出新的可执行文件。

可以通过在新目录中运行每个测试或给临时文件提供唯一名称来解决此问题,但我不想这样做,因为这种方法应该可行,我会只是写一个问题,我不能等待一个过程正常终止。

这是我启动和等待过程的代码:

#include <Windows.h>
#include <iostream>
#include <thread>

class Pipe {
    HANDLE ReadHandle;
    HANDLE writehandle;
public:
    Pipe() {
        SECURITY_ATTRIBUTES saAttr;
        saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
        saAttr.bInheritHandle = TRUE;
        saAttr.lpSecurityDescriptor = NULL;
        CreatePipe(&ReadHandle, &writehandle, &saAttr, 0);
    }
    HANDLE WriteHandle() {
        return writehandle;
    }
    std::string Contents() {
        CloseHandle(writehandle);
        DWORD dwRead;
        CHAR chBuf[1024];
        BOOL bSuccess = FALSE;

        std::string result;
        for (;;)
        {
            bSuccess = ReadFile(ReadHandle, chBuf, 1024, &dwRead, NULL);
            if (!bSuccess || dwRead == 0) break;
            result += std::string(chBuf, chBuf + dwRead);
        }
        return result;
    }
    ~Pipe() {
        CloseHandle(ReadHandle);
    }
};
Wide::Driver::ProcessResult Wide::Driver::StartAndWaitForProcess(std::string name, std::vector<std::string> args, Util::optional<unsigned> timeout)
{
    auto throw_last_err = [] {
        DWORD dw = GetLastError();
        const char* message;
        FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            nullptr, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&message, 0, nullptr);
        std::string err = message;
        LocalFree((void*)message);
        throw std::runtime_error(err);
    };
    ProcessResult result;
    Pipe stdoutpipe;
    Pipe stderrpipe;
    PROCESS_INFORMATION info = { 0 };
    STARTUPINFO startinfo = { sizeof(STARTUPINFO) };
    std::string final_args = name;
    for (auto arg : args)
         final_args += " " + arg;
    startinfo.hStdOutput = stdoutpipe.WriteHandle();
    startinfo.hStdError = stderrpipe.WriteHandle();
    startinfo.hStdInput = INVALID_HANDLE_VALUE;
    startinfo.dwFlags |= STARTF_USESTDHANDLES;
    auto proc = CreateProcess(
        name.c_str(),
        &final_args[0],
        nullptr,
        nullptr,
        TRUE,
        NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,
        nullptr,
        nullptr,
        &startinfo,
        &info
         );
    if (!proc) {
        throw_last_err();        
    }
    if (timeout == 0)
        timeout = INFINITE;

    std::thread writethread([&] {
        result.std_out = stdoutpipe.Contents();
    });
    std::thread errthread([&] {
        result.std_err = stderrpipe.Contents();
    });

    auto waiterr = WaitForSingleObject(info.hProcess, timeout ? *timeout : INFINITE);
    if (waiterr == WAIT_TIMEOUT) {
        TerminateProcess(info.hProcess, 1);
        waiterr = WaitForSingleObject(info.hProcess, timeout ? *timeout : INFINITE);
        if (waiterr != WAIT_OBJECT_0) {
            throw_last_err();
        }
    } else if (waiterr != WAIT_OBJECT_0) {
        throw_last_err();
    }

    writethread.join();
    errthread.join();
    DWORD exit_code;
    GetExitCodeProcess(info.hProcess, &exit_code);
    CloseHandle(info.hProcess);
    CloseHandle(info.hThread);
    result.exitcode = exit_code;
    if (exit_code != 0)
        return result;
    return result;
}

throw_last_err()从未被调用过,所以一切都很好,据说。

为什么我不能等待这个过程?

1 个答案:

答案 0 :(得分:1)

根据评论,搜索等各种Windows组件可以锁定随机文件。这对我来说意味着,一般来说,我不能假设文件不会被锁定,因此我不能假设我可以立即重新使用它。

因此,我决定不再重复使用中间文件。