Osztály megvalósítása, amely időtúllépéssel futtat egy gyermekfolyamatot a boost folyamat segítségével aszinkron módban

A következő kódban egy olyan programot próbálok megvalósítani, amely egy feldolgozza, és visszaadja visszatérési kódját, stdout és stderr. Van egy időkorlát koncepciója is, amely után a gyermek folyamatát megölik. Ezt az osztályt egy több szálon futó alkalmazás részeként fogják használni.

#ifndef PROCESS_H_ #define PROCESS_H_ //Header #include <chrono> #include <thread> #include <iostream> #include <boost/process.hpp> #include <boost/asio.hpp namespace bp = boost::process; class Proces { public: Process(const std::string& cmd, const int timeout); void run(); int getReturnStatus(); //Must be only called after run() exits std::string getStdOut(); //Must be only called after run() exits std::string getStdErr(); //Must be only called after run() exits bool wasKilled(); //Must be only called after run() exits private: void initLog(); void timeoutHandler(const boost::system::error_code& ec); void kill(); const std::string command; const int timeout; int returnStatus; std::string stdOut; std::string stdErr; bool killed; bool stopped; boost::process::group group; boost::asio::io_context ioc; boost::asio::deadline_timer deadline_timer; }; #endif //Source #include "Process.h" Process::Process(const std::string& cmd, const int timeout): command(cmd), timeout(timeout), returnStatus(0), stdOut(""), stdErr(""), killed(false), stopped(false), ioc(), deadline_timer(ioc) { } void Process::timeoutHandler(const boost::system::error_code& ec) { if (stopped || ec == boost::asio::error::operation_aborted) { return; } std::cout << "Time Up!"<< std::endl; kill(); deadline_timer.expires_at(boost::posix_time::pos_infin); } void Process::run() { std::future<std::string> dataOut; std::future<std::string> dataErr; std::cout << "Running command: " << command << std::endl; bp::child c(command, bp::std_in.close(), bp::std_out > dataOut, bp::std_err > dataErr, ioc, group, bp::on_exit([=](int e, const std::error_code& ec) { std::cout << "on_exit: " << ec.message() << " -> " << e << std::endl; deadline_timer.cancel(); returnStatus = e; })); deadline_timer.expires_from_now(boost::posix_time::seconds(timeout)); deadline_timer.async_wait(std::bind(&Process::timeoutHandler, this, std::placeholders::_1)); ioc.run(); c.wait(); stdOut = dataOut.get(); stdErr = dataErr.get(); } //Must be only called after run() exits int Process::getReturnStatus() { return returnStatus; } //Must be only called after run() exits std::string Process::getStdOut() { return stdOut; } //Must be only called after run() exits std::string Process::getStdErr() { return stdErr; } void Process::kill() { std::error_code ec; group.terminate(ec); if(ec) { std::cout << "Error occurred while trying to kill the process: " << ec.message(); throw std::runtime_error(ec.message()); } std::cout << "Killed the process and all its descendants" << std::endl; killed = true; stopped = true; } //Must be only called after run() exits bool Process::wasKilled() { return killed; } 

Az alábbiakban a kódot használom, amelyet tesztelni használok

#define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE ProcessTest #include <boost/test/unit_test.hpp> #include "../src/Process.h" BOOST_AUTO_TEST_CASE( ProcessTest ) { const std::vector<std::string> commands = { "ls" , "pwd" , "uname -a" , "cat /proc/cpuinfo" , "wget https://dl.google.com/dl/earth/client/current/google-earth-pro-stable-current.x86_64.rpm"}; for(const auto& cmd: commands) { Process p(cmd, 3600); p.run(); BOOST_CHECK( p.getReturnStatus() == 0); // #1 continues on error } const std::vector<std::string> commandsThatShouldFail = { "ls doesnotexit" , "cat /proc/doesnotexist" , "wget https://dl.google.com/dl/earth/client/current/doesnotxist.rpm"}; for(const auto& cmd: commandsThatShouldFail) { Process p(cmd, 3600); p.run(); BOOST_CHECK( p.getReturnStatus() != 0); // #1 continues on error } } 

Kérjük, adja meg értékes észrevételeit és javaslatait.

Megjegyzések

  • Üdvözöljük a Code Review oldalán! Azt mondja, hogy ' megpróbálja végrehajtani a programot. Eddig működik? Van valami aggályod a kódoddal kapcsolatban? ' rendben van, ha nem ' t, mindaddig, amíg a kód rendeltetésszerűen működik.
  • @Mast A kód azokra az esetekre működik, amelyeknél teszteltem. De kíváncsi vagyok, vannak-e versenykörülmények és egyéb hibák?
  • Jó! Felvenné ezeket a teszteket?

Válasz

Még mindig szoktam Boost::Process, szóval talán ezt tévedtem. Szüksége van azonban a c.wait() -re a ios.run() után?

A dokumentáció , a vezérlés blokkolva lesz a ios.run() címen, amíg a io_context be nem fejeződik, vagy természetesen, ha a deadline_timer lejár.

Válasz

Hiányzó tesztek

I ne lásson olyan parancsokat, amelyeknek időtúllépniük kellene. Nyilvánvaló példa lehet a sleep 2, ha 1. Egy szigorúbb teszt egy olyan parancs lenne, amely figyelmen kívül hagy minden jelet (azok közül, amelyeket figyelmen kívül lehet hagyni) – biztosítanunk kell, hogy ha a SIGTERM nem működik, akkor megkapja SIGKILL végül.

Adatvezérelt tesztek

Nem szeretnék ciklusokat látni a teszt esetekben. Rendelkezik-e a Boost Test a tesztek megismétlése különböző adatokkal? A legtöbb tesztkeret igen; Meglepődnék, ha m lenne a Boost-tól.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük