Home > OS >  How to wait for thread to finish execution?
How to wait for thread to finish execution?

Time:09-03

Is there a way to check if the child process created with CreateThread has finished execution

This code does print the output of the command but only when a proper wait time is added to WaitForSingleObject in this case 5 seconds is enough but this is not always the case

#define BUFSIZE 4096


HANDLE g_hChildStd_IN_Rd = NULL;
HANDLE g_hChildStd_IN_Wr = NULL;
HANDLE g_hChildStd_OUT_Rd = NULL;
HANDLE g_hChildStd_OUT_Wr = NULL;
HANDLE handle = NULL;



DWORD grab_output(void * args)
{   
   DWORD dwRead, total=0; 
   CHAR chBuf[BUFSIZE]; 
   BOOL bSuccess = FALSE;
   for (;;) 
   { 
      bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
      if( ! bSuccess ) break;
        printf("%s", chBuf);

    }
    printf("\n");
    return 0;
}

int run()
{
    BOOL res; 
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    SECURITY_ATTRIBUTES sa;
    
    DWORD n_size; 
    
    memset(&pi, 0, sizeof(pi));
    memset(&sa, 0, sizeof(sa));
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.bInheritHandle = TRUE;
    sa.lpSecurityDescriptor = NULL;

    if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &sa, 0)) 
        return GetLastError();
    
    if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
        return GetLastError();

    memset(&si, 0 ,sizeof(si));
    si.cb = sizeof(STARTUPINFOA);
    si.hStdError = g_hChildStd_OUT_Wr;
    si.hStdOutput = g_hChildStd_OUT_Wr; 
    si.dwFlags |= STARTF_USESTDHANDLES;

    if(!CreateProcess(NULL,              
                        "C:\\Windows\\System32\\cmd.exe /c ping google.com",    
                        NULL,    
                        NULL,   
                        TRUE,         
                        CREATE_NO_WINDOW, 
                        NULL,
                        NULL,                              
                        &si,              
                        &pi                 
                        ))
                        {
    }
    else
    {
        handle = CreateThread(0, 0, grab_output, NULL, 0, NULL);
        WaitForSingleObject(handle, INFINITE);
    }
    return 0;
}


int main()
{
    run();
    return 0;
}

I tried using GetExitCodeThread in the run function but it does not seem to work properly and keeps outputting the same exit code before and after the child has finished execution, I also tried using WaitForSingleObject and I checked the return code but it too keeps outputting WAIT_TIMEOUT

the output

$ gcc temp2.c && ./a.exe 

Pinging google.com [172.217.168.238] with 32 bytes of data:
2.217.168.238] Reply from 172.217.168.238: 7.168.238] bytes=32 time=87ms TTL=57
 7.168.238] Reply from 172.217.168.238: 7.168.238] bytes=32 time=96ms TTL=57
 7.168.238] Reply from 172.217.168.238: 7.168.238] bytes=32 time=86ms TTL=57
 7.168.238] Reply from 172.217.168.238: 7.168.238] bytes=32 time=86ms TTL=57

Ping statistics for 172.217.168.238:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 86ms, Maximum = 96ms, Average = 88ms


this never seems to return back the console because of INFINITE

How do I properly check if the child process has finished execution

CodePudding user response:

Your entire code and explanation make literally no sense.

the child process created with CreateThread

CreateThread doesn't create processes, this isn't Linux.

   if(!CreateProcess(NULL,              
                    "C:\\Windows\\System32\\cmd.exe /c ping google.com",    
                    NULL,    
                    NULL,   
                    TRUE,         
                    CREATE_NO_WINDOW, 
                    NULL,
                    NULL,                              
                    &si,              
                    &pi                 
                    ))
                    {

You create a process and don't store it's handle anywhere, what is your thinking here?

I tried using GetExitCodeThread in the run function but it does not seem to work properly

Blaming your tools because you use them wrong peg your skill level as a programmer very appropriately. How can you even check the exit code if you don't store the process handle anywhere?

I also tried using WaitForSingleObject

Not on your process you didn't, you used it on some random thread you felt like creating for no reason.

In short, if you insist on doing things the wrong, brittle, inefficient and un-portable way, store your process handle and use WaitForSingleObject on it. If you want to wait until it's over (ie freeze your application until then, which is in line with the rest of your code), use an INFINITE parameter. If you want to simply check if it's done, use 0.

Otherwise, use IcmpSendEcho2 like I said.

CodePudding user response:

Blindy's concerns are valid if you intend to wait for the process to exit. If you instead intend to wait until your thread reads all output from the process (and you should), the fix is much simpler.

In this loop, you failed to account for the "end of file" condition:

for (;;) 
{ 
   bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
   if( ! bSuccess ) break;
   printf("%s", chBuf);
}

End-of-file is indicated by a successful read with zero length.

You also call printf on data that isn't NUL-terminated.

Fixing both those issues:

for (;;) { 
   bSuccess = ReadFile(g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
   if (!bSuccess) break;
   if (dwRead == 0) break;
   fwrite(chBuf, 1, dwRead, stdout);
}

Now, when the child process exits, it will close its pipe handle. Your reading thread will read an end-of-file and exit its loop, but only after printing all the data it read from the pipe. Returning from your thread procedure will wake the WaitForSingleObject waiting on the thread.

Following Blindy's advice would exit your program too early, without the "only after printing all the data it read from the pipe" behavior.

However, Blindy is right that you didn't have any particular reason to create that thread. You could just call grab_output(nullptr) instead. With the above fixes, that will work perfectly.

  • Related