Richard
Richard

Reputation: 389

How to find out whether child process still is running?

I am spawning a process in my application:

int status = posix_spawnp(&m_iProcessHandle, (char*)strProgramFilepath.c_str(), NULL, NULL, argsWrapper.m_pBuffer, NULL);

When I want to see if the process is still running, I use kill:

int iReturn = kill(m_iProcessHandle,0);

But after the spawned process has finished its work, it hangs around. The return value on the kill command is always 0. Not -1. I am calling kill from within the code, but if I call it from the command line, there is no error - the spawned process still exists.

Only when my application exits does the command-line kill return "No such process".

I can change this behavior in my code with this:

int iResult = waitpid(m_iProcessHandle, &iStatus, 0);

The call to waitpd closes down the spawned process and I can call kill and get -1 back, but by then I know the spawned process is dead.

And waitpd blocks my application!

How can I test a spawned processes to see if it is running, but without blocking my application?

UPDATE

Thanks for the help! I have implemented your advise and here is the result:

// background-task.cpp
//

#include <spawn.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>

#include "background-task.h"


CBackgroundTask::CBackgroundTask()
{

    // Initialize member variables
    m_iProcessHandle = 0;

}

CBackgroundTask::~CBackgroundTask()
{

    // Clean up (kill first)
    _lowLevel_cleanup(true);

}

bool CBackgroundTask::IsRunning()
{

    // Shortcuts
    if (m_iProcessHandle == 0)
        return false;

    // Wait for the process to finish
    int iStatus = 0;
    int iResult = waitpid(m_iProcessHandle, &iStatus, WNOHANG);
    return (iResult != -1);

}

void CBackgroundTask::Wait()
{

    // Wait (clean up without killing)
    _lowLevel_cleanup(false);

}

void CBackgroundTask::Stop()
{

    // Stop (kill and clean up)
    _lowLevel_cleanup(true);

}

void CBackgroundTask::_start(const string& strProgramFilepath, const string& strArgs, int iNice /*=0*/)
{

    // Call pre-start
    _preStart();

    // Split the args and build array of char-strings
    CCharStringAarray argsWrapper(strArgs,' ');

    // Run the command
    int status = posix_spawnp(&m_iProcessHandle, (char*)strProgramFilepath.c_str(), NULL, NULL, argsWrapper.m_pBuffer, NULL);
    if (status == 0)
    {

        // Process created
        cout << "posix_spawn process=" << m_iProcessHandle << "  status=" <<     status << endl;

    }
    else
    {

        // Failed
        cout << "posix_spawn: error=" << status << endl;

    }

    // If process created...
    if(m_iProcessHandle != 0)
    {

        // If need to adjust nice...
        if (iNice != 0)
        {

            // Change the nice
            stringstream ss;
            ss << "sudo renice -n " << iNice << " -p " << m_iProcessHandle;
            _runCommand(ss.str());

        }

    }
    else
    {

        // Call post-stop success=false
        _postStop(false);

    }

}

void CBackgroundTask::_runCommand(const string& strCommand)
{

    // Diagnostics
    cout << "Running command: " << COUT_GREEN << strCommand << endl << COUT_RESET;

    // Run command
    system(strCommand.c_str());

}

void CBackgroundTask::_lowLevel_cleanup(bool bKill)
{

    // Shortcuts
    if (m_iProcessHandle == 0)
        return;

    // Diagnostics
    cout << "Cleaning up process " << m_iProcessHandle << endl;

    // If killing...
    if (bKill)
    {

        // Kill the process
        kill(m_iProcessHandle, SIGKILL);

    }

    // Diagnostics
    cout << "Waiting for process " << m_iProcessHandle << " to finish" << endl;

    // Wait for the process to finish
    int iStatus = 0;
    int iResult = waitpid(m_iProcessHandle, &iStatus, 0);

    // Diagnostics
    cout << "waitpid: status=" << iStatus << "   result=" << iResult << endl;

    // Reset the process-handle
    m_iProcessHandle = 0;

    // Call post-stop with success
    _postStop(true);

    // Diagnostics
    cout << "Process cleaned" << endl;

}

Upvotes: 0

Views: 1822

Answers (1)

Barmar
Barmar

Reputation: 780714

Until the parent process calls one of the wait() functions to get the exit status of a child, the child stays around as a zombie process. If you run ps during this time, you'll see that the process is still there in the Z state. So kill() returns 0 because the process exists.

If you don't need to get the child's status, see How can I prevent zombie child processes? for how you can make the child disappear immediately when it exits.

Upvotes: 3

Related Questions