Программа зависает после вызова std :: future.get () с использованием Boost.Process для асинхронного

Я создаю программу, которая выполняет несколько исполняемых файлов асинхронно. Моя проблема в том, что когда я звоню получить() функция от станд :: будущее, моя программа зависает без ошибок.

Я использую Boost.Process для управления процессами, а также wxWidgets в других местах.

Моя программа создает указатель на новый BProcess, содержащий std :: future. Позднее функция таймера проверяет каждые несколько миллисекунд, чтобы увидеть, завершен ли каждый процесс.

class BProcess
{
public:
BProcess();
boost::asio::io_service ios;
boost::process::child child_process;
std::future<std::string> future_result;
};

void Module::Execute() //done for each process
{
this->process_handle = new BProcess();
this->process_handle->child_process = boost::process::child(sfilename, boost::process::std_out > this->process_handle->future_result, this->process_handle->ios);
}

void Timer::Notify()
{
//done in loop for each Module - hangs after first module finishes
if (!Modules[i].process_handle->child_process.running())
{
std::string testStr = Modules[i].process_handle->future_result.get();
}
}

РЕДАКТИРОВАТЬ: Вот вывод «где» из GDBЯ хотел попытаться выяснить, что происходит. Имеет ли это смысл для кого-либо?

Timer Started!
Module 0 set to run.
Module 1 set to run.
Module 2 set to run.
You checked/unchecked that item: 1
Executing Module #0
Detaching after fork from child process 17066.
Detaching after fork from child process 17069.
You checked/unchecked that item: 1
Executing Module #1
Detaching after fork from child process 17071.
Detaching after fork from child process 17072.
You checked/unchecked that item: 1
Executing Module #2
Detaching after fork from child process 17074.
Detaching after fork from child process 17075.
[New Thread 0xf5bffb40 (LWP 17078)]
[Thread 0xf33ffb40 (LWP 17063) exited]
Done Executing Module #0
^C
Thread 1 "SecureIT" received signal SIGINT, Interrupt.
0xf7fd3db9 in __kernel_vsyscall ()
Missing separate debuginfos, use: dnf debuginfo-install expat-2.2.4-1.fc26.i686 fontconfig-2.12.6-3.fc26.i686 gdk-pixbuf2-2.36.9-1.fc26.i686 gdk-pixbuf2-modules-2.36.9-1.fc26.i686 libblkid-2.30.2-1.fc26.i686 libffi-3.1-12.fc26.i686 libgcc-7.2.1-2.fc26.i686 libglvnd-0.2.999-24.20170818git8d4d03f.fc26.i686 libglvnd-egl-0.2.999-24.20170818git8d4d03f.fc26.i686 libglvnd-glx-0.2.999-24.20170818git8d4d03f.fc26.i686 libmount-2.30.2-1.fc26.i686 libselinux-2.6-7.fc26.i686 libstdc++-7.2.1-2.fc26.i686 libuuid-2.30.2-1.fc26.i686 pango-1.40.12-1.fc26.i686 pcre-8.41-1.fc26.i686
(gdb) where
#0  0xf7fd3db9 in __kernel_vsyscall ()
#1  0xf6f6e327 in syscall () at /lib/libc.so.6
#2  0xf7166fdb in std::__atomic_futex_unsigned_base::_M_futex_wait_until(unsigned int*, unsigned int, bool, std::chrono::duration<long long, std::ratio<1ll, 1ll> >, std::chrono::duration<long long, std::ratio<1ll, 1000000000ll> >) () at /lib/libstdc++.so.6
#3  0x080cf683 in std::__atomic_futex_unsigned<2147483648u>::_M_load_and_test_until(unsigned int, unsigned int, bool, std::memory_order, bool, std::chrono::duration<long long, std::ratio<1ll, 1ll> >, std::chrono::duration<long long, std::ratio<1ll, 1000000000ll> >) (this=0x8b804e4, __assumed=0, __operand=1, __equal=true, __mo=std::memory_order_acquire, __has_timeout=false, __s=..., __ns=...) at /usr/include/c++/7/bits/atomic_futex.h:102
#4  0x080cf09b in std::__atomic_futex_unsigned<2147483648u>::_M_load_and_test(unsigned int, unsigned int, bool, std::memory_order) (this=0x8b804e4, __assumed=0, __operand=1, __equal=true, __mo=std::memory_order_acquire) at /usr/include/c++/7/bits/atomic_futex.h:122
#5  0x080ce61a in std::__atomic_futex_unsigned<2147483648u>::_M_load_when_equal(unsigned int, std::memory_order) (__mo=std::memory_order_acquire, __val=1, this=0x8b804e4) at /usr/include/c++/7/bits/atomic_futex.h:162
#6  0x080ce61a in std::__future_base::_State_baseV2::wait() (this=0x8b804dc) at /usr/include/c++/7/future:337
#7  0x080cf592 in std::__basic_future<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::_M_get_result() const (this=0x8b80c48) at /usr/include/c++/7/future:717
#8  0x080ceff8 in std::future<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::get() (this=0x8b80c48)
at /usr/include/c++/7/future:796
#9  0x080cdc8b in ExecuteTimer::Notify() (this=0x8bbd460) at ExecuteTimer.cpp:35
#10 0x0833efbf in timeout_callback ()
#11 0xf7415c13 in g_timeout_dispatch (source=source@entry=0x8b80c80, callback=0x833ef80 <timeout_callback>, user_data=0x8bbde00) at gmain.c:4715
#12 0xf7414fc9 in g_main_dispatch (context=0x8a1f698) at gmain.c:3234
#13 0xf7414fc9 in g_main_context_dispatch (context=context@entry=0x8a1f698) at gmain.c:3899
#14 0xf74153f0 in g_main_context_iterate (context=0x8a1f698, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3972
#15 0xf74157a1 in g_main_loop_run (loop=loop@entry=0x8abf0f0) at gmain.c:4168
#16 0xf7afcc50 in IA__gtk_main () at gtkmain.c:1268
#17 0x08335fc5 in wxGUIEventLoop::DoRun() ()
#18 0x083c0393 in wxEventLoopBase::Run() ()
#19 0x08391921 in wxAppConsoleBase::MainLoop() ()
#20 0x084071db in wxEntry(int&, wchar_t**) ()
#21 0x08083e55 in main(int, char**) (argc=1, argv=0xffffd194) at main.cpp:13
(gdb)

Любая помощь будет оценена. Скажите, если я не показываю достаточно кода.

2

Решение

Я думаю, вы можете просто забыть / пренебречь запуском io_service.

Вот грубый набросок.

Обратите внимание, что есть несколько проблем дизайна:

  • проверка running() это очень Если он никогда не бежал, ты тост. Если вы уже получили будущую стоимость раньше, вы тост.
  • Почему вы опрашиваете по таймеру, когда вы запускаете процессы асинхронно в любом случае? Вы можете просто ответить на событие завершения.
  • Закон Деметры, вероятно, должен применяться к вашим типам

Жить на Колиру

#include <boost/process.hpp>
#include <boost/process/async.hpp>
#include <list>
#include <memory>

struct BProcess {
BProcess(boost::asio::io_service& svc) : ios(svc) {}

void Execute(std::string const& sfilename) {
namespace bp = boost::process;
child_process = bp::child(sfilename, bp::std_out > output, ios);
}

boost::asio::io_service& ios;
boost::process::child child_process;
std::future<std::string> output;
};

struct Module {
Module(boost::asio::io_service& svc) : ios(svc), process(new BProcess(svc)) {}

void Execute(std::string const& sfilename) {
process->Execute(sfilename);
}

bool running() const { return process->child_process.running(); }
std::string get_output() const { return process->output.get(); }

private:
boost::asio::io_service& ios;
std::unique_ptr<BProcess> process;
};

#include <iostream>

struct Timer {
std::list<Module> Modules;

void Notify() {
for (auto& m : Modules) {
if (!m.running()) {
std::string testStr = m.get_output();
std::cout << "Got " << testStr.size() << " bytes of output\n";
std::cout << "---- '" << testStr << "' ---\n";
}
}
}
};

int main() {
boost::asio::io_service ios;

Timer timer;
timer.Modules.emplace_back(ios);
timer.Modules.back().Execute("/usr/bin/find");

timer.Modules.emplace_back(ios);
timer.Modules.back().Execute("/usr/bin/gcc");

for (auto& m : timer.Modules)
m.Execute("/usr/bin/find");

ios.run();
timer.Notify();
}
1

Другие решения

Других решений пока нет …