2015-09-10 3 views
0

Я порождая процесс в моем приложении:Как узнать, работает ли дочерний процесс?

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

Когда я хочу увидеть, если процесс все еще работает, я использую убить:

int iReturn = kill(m_iProcessHandle,0); 

Но после порожденного процесса завершил свою работу , он висит вокруг. Возвращаемое значение команды kill всегда равно 0. Не -1. Я вызываю kill из кода, но если я его вызову из командной строки, ошибки нет - процесс порождения все еще существует.

Только когда мое приложение выходит из командной строки, команда kill возвращает «Нет такого процесса».

я могу изменить это поведение в моем коде с этим:

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

Вызов waitpd закрывает вниз порождал процесс, и я могу позвонить убить и получить -1 обратно, но к тому времени я знаю порождал процесс мертв.

И waitpd блокирует мое приложение!

Как я могу протестировать порожденные процессы, чтобы увидеть, работает ли он, но не блокирует мое приложение?

UPDATE

Спасибо за помощь! Я выполнил свою консультацию, и вот результат:

// 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; 

} 
+4

Вы пытались использовать опцию 'WNOHANG' для' waitpid'? – 5gon12eder

+3

Инициализированный процесс (даже если он завершен, а затем называется * зомби *) содержит идентификатор процесса, пока родитель правильно * не вытащит * ребенка через 'wait()' и друзей. Если вы хотите асинхронное уведомление, установите обработчик для 'SIGCHLD' (и вызовите' wait() 'оттуда). – dhke

+1

FYI, «wait» в waitpid (...) является немного неправильным. Основная цель wait (...) и друзей - получить статус процесса «зомби», чтобы ядро ​​могло фактически убить его и повторно использовать его идентификатор процесса. Тот факт, что wait() и друзья _wait_ для процесса входа в состояние зомби (если вы не указали 'WNOHANG'), является вторичной функцией. –

ответ

3

Пока родительский процесс не вызывает один из wait() функций, чтобы получить статус выхода ребенка, ребенок остается вокруг как zombie process. Если вы запустите ps за это время, вы увидите, что процесс все еще находится в состоянии Z. Итак, kill() возвращает 0, потому что процесс существует.

Если вам не нужно получить статус ребенка, см. How can I prevent zombie child processes?, как вы можете заставить ребенка немедленно исчезнуть, когда он выйдет.

Смежные вопросы