0

My call to ReadFile is deadlocking, and I believe this to be the problem described here: http://blogs.msdn.com/b/oldnewthing/archive/2011/07/07/10183884.aspx

Unfortunately, I am still unable to make my code work. I'm actually not trying to write anything to stdin, but I guess I must be in some way I don't realise. I've tried creating a second thread, but I can't figure out which bit of the operation is supposed to go in that thread.

I'll include my code below. I'm sorry there's so much of it, but I've tried to strip it down to the minimum, and I've only included my process creation code.

I've tried moving the orders of the various parts around, but I can't get it to work in any order. The code seems to work for small outputs, but not for large outputs, but I need large outputs.

class STDOUT_WORK_ITEM
{
public:
    HANDLE g_hChildStd_OUT_Rd;
    std::wstringstream& ss;

    STDOUT_WORK_ITEM(HANDLE _g_hChildStd_OUT_Rd, std::wstringstream& _ss) : g_hChildStd_OUT_Rd (_g_hChildStd_OUT_Rd), ss(_ss) { };
};

unsigned int _stdcall InternalCreateProcessStdOutHelperThread (void* param)
{
    DWORD dwRead;
    char chBuf[4096] = { 0 };
    BOOL bSuccess = FALSE;

    for (;;)
    {
        bSuccess = ReadFile(reinterpret_cast<STDOUT_WORK_ITEM*>(param)->g_hChildStd_OUT_Rd, chBuf, 4096, &dwRead, NULL);
        if(!bSuccess || dwRead == 0)
            break;
        std::string temp = chBuf;
        reinterpret_cast<STDOUT_WORK_ITEM*>(param)->ss << std::wstring(temp.begin(), temp.end());
        if (dwRead < 4096)
            break;
        ZeroMemory(chBuf, dwRead);
    }
    _endthreadex(ERROR_SUCCESS);
    return ERROR_SUCCESS;
}

bool function(...)
{
    bool _return = true;

    HANDLE g_hChildStd_OUT_Rd = NULL;
    HANDLE g_hChildStd_OUT_Wr = NULL;

    STARTUPINFO         siStartupInfo;
    PROCESS_INFORMATION piProcessInfo;

    memset(&siStartupInfo, 0, sizeof(siStartupInfo));
    memset(&piProcessInfo, 0, sizeof(piProcessInfo));

    siStartupInfo.cb = sizeof(siStartupInfo);

    LPWSTR szCmdline = _wcsdup(ExpandEnvironmentVariables(path).c_str());
    LPWSTR szParameters = _wcsdup(args.c_str());


    SECURITY_ATTRIBUTES saAttr;
    memset(&saAttr, 0, sizeof(saAttr));

    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, NULL))
        _return = false;

    if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, NULL))
        _return = false;

    if (!_return)
    {
        CloseHandle(g_hChildStd_OUT_Rd);
        CloseHandle(g_hChildStd_OUT_Wr);
        free(szParameters);
        free(szCmdline);
        return false;
    }

    siStartupInfo.hStdError  = g_hChildStd_OUT_Wr;
    siStartupInfo.hStdOutput = g_hChildStd_OUT_Wr;
    siStartupInfo.dwFlags   |= STARTF_USESTDHANDLES;



    if(CreateProcess(szCmdline, szParameters, NULL, NULL, stdOUT != NULL ? TRUE : FALSE, CREATE_NO_WINDOW, NULL, NULL, &siStartupInfo, &piProcessInfo) == FALSE)
    {
        // Fail
    }


    WaitForSingleObject(piProcessInfo.hProcess, INFINITE);
    GetExitCodeProcess(piProcessInfo.hProcess, exit_code);


    std::wstringstream ss;

    HANDLE hStdOutWorkMutex = CreateMutex(NULL, FALSE, NULL);
    HANDLE hStdOutThread = (HANDLE)_beginthreadex(NULL, NULL, InternalCreateProcessStdOutHelperThread, &STDOUT_WORK_ITEM(g_hChildStd_OUT_Rd, ss), NULL, NULL);
    WaitForSingleObject(hStdOutThread, INFINITE);

    // Collect output from ss.str();

    CloseHandle(g_hChildStd_OUT_Rd);
    CloseHandle(g_hChildStd_OUT_Wr);

    CloseHandle(piProcessInfo.hProcess);
    CloseHandle(piProcessInfo.hThread);
    free(szParameters);
    free(szCmdline);

    return _return;
}

Unfortunately, ReadFile still deadlocks. Thank you very much for any help you can offer.

niemiro
  • 1,778
  • 1
  • 20
  • 37
  • You are waiting for the process to complete, then read its output. That's deadlock city, the process will block when it cannot flush its stdout or stderr buffer. You of course need to start the reader thread *before* you wait for the process to complete. – Hans Passant May 25 '14 at 13:18
  • Thank you very much for your help here. I think I must have a second problem though, because when I move the thread creation code to immediately after the CreateProcess call, ReadFile still hangs. What is the correct structure of the code meant to be? CreatePipe, SetHandleInformation, CreateProcess, create thread, ReadFile on that thread, wait for thread to complete, wait for process to complete? Thank you again. – niemiro May 25 '14 at 15:28
  • I've got it working :) It turns out that I needed to close g_hChildStd_OUT_Wr as described here: http://stackoverflow.com/questions/10841840/win32-readfile-from-pipe-block-even-after-child-terminated. Thanks again for your help with the first problem :) – niemiro May 25 '14 at 16:08

0 Answers0