Luokan toteutus, joka suorittaa aliprosessin aikakatkaisulla käyttämällä boost-prosessia asynkronisessa tilassa

Seuraavassa koodissa yritän toteuttaa ohjelman, joka suorittaa prosessin ja palauttaa palautuskoodinsa, stdout ja stderr. Sillä on myös aikakatkaisun käsite, jonka jälkeen lapsiprosessi tapetaan. Tätä luokkaa käytetään osana monisäikeistä sovellusta.

#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; } 

Alla on koodi, jota käytän sen testaamiseen

#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 } } 

Anna arvokkaat kommenttisi ja ehdotuksesi.

kommentit

  • Tervetuloa Code Review -sovellukseen! Sanot, että yrität ' toteuttaa ohjelmaa. Toimiiko se toistaiseksi? Onko sinulla huolta koodistasi? ' on ok, jos et ' t, kunhan koodi toimii tarkoitetulla tavalla.
  • @Mast Koodi toimii tapauksissa, joissa olen testannut sitä. Mutta mietin, onko kilpailuolosuhteita ja muita vikoja?
  • Hyvä! Voisitko sisällyttää nuo testit?

Vastaa

Olen vielä tottunut Boost::Process, joten ehkä olen erehtynyt tästä. Tarvitsetko kuitenkin todella c.wait() ios.run() jälkeen?

Kuten heidän dokumentaatio , ohjaus estetään osoitteessa ios.run(), kunnes io_context on valmis tai tietysti, jos deadline_timer vanhenee.

Vastaa

Puuttuvat testit

I älä näe komentoja testeille, joiden pitäisi aikakatkaistua. Ilmeinen esimerkki voi olla sleep 2, jos suoritamme sen aikakatkaisulla 1. Tiukempi testi olisi komento, joka jättää huomiotta kaikki signaalit (jotka voidaan jättää huomioimatta) – meidän on varmistettava, että jos SIGTERM ei toimi, niin se saa SIGKILL lopulta.

Tietopohjaiset testit

En halua nähdä silmukoita testitapauksissa. Onko Boost Testissä toistetaan testejä eri tiedoilla? Useimmat testikehykset tekevät; olisin yllättynyt, jos se olisi m issing from Boost.

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *