boost :: process как узнать, завершился ли процесс корректно или нет?

В ожидании boost::process::child, как узнать, завершился ли он "изящно или нет"?

Допустим, я создаю процесс:

boost::process::child child( "myprg.exe", "5000" );
child.wait();
int res = child.exit_code();

Где myprg.exe:

int main( int argc, char* argv[] )
{
    if ( argc == 2 )
    {
        boost::this_thread::sleep( boost::posix_time::milliseconds( atoi( argv[1] ) ) );
        return 1;
    }

    return 0;
}

Примечание: это MCVE, который не имеет смысла, я согласен, что main должен возвращать 0 в случае успеха.

Я вижу, что если кто-то убивает процесс во время ожидания (например, с помощью child.terminate или диспетчера процессов Windows), child.exit_code() вернет 1.

Итак, в конце концов, когда child.exit_code() равно 1, как я могу узнать, является ли это значение, возвращаемое основной функцией входа в процесс, или процесс был убит?

Гарантировано ли, что 1 будет означать, что процесс был убит? Тогда программа не должна возвращать 1 и сохранять этот код выхода, чтобы определить конкретную ситуацию, когда она была убита и не завершилась чисто?

Если нет, предоставляет ли boost::process API что-нибудь, чтобы узнать, закончился ли процесс корректно или был убит?


person jpo38    schedule 04.12.2017    source источник
comment
Насколько я помню, не существует независимого от платформы способа, но вы можете добиться чего-то, используя группу процессов и обрабатывая сигналы CHLD. То есть: нарушение абстракции API ускоренного процесса.   -  person sehe    schedule 04.12.2017


Ответы (2)


Итак, в конце концов, когда child.exit_code() равно 1, как я могу узнать, является ли это значение, возвращаемое основной функцией входа в процесс, или процесс был убит?

Вы не можете.

Гарантировано ли, что 1 будет означать, что процесс был убит?

По-разному. Что касается Windows, согласно этому ответу, это будет 1, но это нигде не задокументировано. Обратите внимание, что код возврата для прекращенного процесса определяется экземпляром, завершающим процесс. Для функции завершения Boost можно найти внутри detail / windows / terminate.hpp:

inline void terminate(child_handle &p)
{
    if (!::boost::winapi::TerminateProcess(p.process_handle(), EXIT_FAILURE))
        boost::process::detail::throw_last_error("TerminateProcess() failed");

    ::boost::winapi::CloseHandle(p.proc_info.hProcess);
    p.proc_info.hProcess = ::boost::winapi::INVALID_HANDLE_VALUE_;
}

Таким образом, он всегда возвращает EXIT_FAILURE, что может быть равно 1. Однако можно заставить процесс возвращать любое значение.

Чтобы отличить, завершен ли ваш процесс корректно или нет, полностью защищенным и переносимым способом, вам, следовательно, необходимо реализовать свой собственный механизм связи, помимо простой оценки кодов возврата.

person Jodocus    schedule 04.12.2017

Вы можете настроить обработчик ошибок в дочернем процессе, чтобы он возвращал другой код выхода. Например, добавьте std :: set_terminate из библиотеки STL:

int main( int argc, char* argv[] )
{
    std::set_terminate([](){ exit(2); });
    if ( argc == 2 )
    {        
        boost::this_thread::sleep(boost::posix_time::milliseconds(atoi(argv[1])));
        return 1;
    }
    return 0;
}
person Nayfe    schedule 04.12.2017