Я порождаю процесс в моем приложении:
int status = posix_spawnp(&m_iProcessHandle, (char*)strProgramFilepath.c_str(), NULL, NULL, argsWrapper.m_pBuffer, NULL);
Когда я хочу посмотреть, запущен ли процесс, я использую kill:
int iReturn = kill(m_iProcessHandle,0);
Но после того, как порожденный процесс закончил свою работу, он зависает. Возвращаемое значение в команде kill всегда равно 0. Не -1. Я вызываю kill из кода, но если я вызываю его из командной строки, ошибки нет — порожденный процесс все еще существует.
Только когда мое приложение завершает работу, команда kill командной строки возвращает «Нет такого процесса».
Я могу изменить это поведение в моем коде с помощью этого:
int iResult = waitpid(m_iProcessHandle, &iStatus, 0);
Вызов waitpd закрывает порожденный процесс, и я могу вызвать kill и получить -1 обратно, но к тому времени я знаю, что порожденный процесс мертв.
И waitpd блокирует мое приложение!
Как я могу протестировать порожденные процессы, чтобы увидеть, запущен ли он, но не блокируя мое приложение?
ОБНОВИТЬ
Спасибо за помощь! Я выполнил ваш совет и вот результат:
// 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;
}
Пока родительский процесс не вызывает один из wait()
функции, чтобы получить статус выхода ребенка, ребенок остается как процесс зомби. Если вы бежите ps
в течение этого времени вы увидите, что процесс все еще существует в Z
государство. Так kill()
возвращается 0
потому что процесс существует.
Если вам не нужно получать статус ребенка, см. Как я могу предотвратить дочерние процессы зомби? за то, как вы можете заставить ребенка исчезнуть сразу после его выхода.