2

我正在创建一个异步执行多个可执行文件的程序。我的问题是,当我从std::future调用get()函数时,我的程序挂断而没有错误。

我正在使用 Boost.Process 来管理进程以及其他地方的 wxWidgets。

我的程序创建了一个指向包含 std::future 的新 BProcess 的指针。计时器函数稍后每隔几毫秒检查一次,以查看每个进程是否已完成。

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 的“where”的输出:我想弄清楚发生了什么。这对任何人都有意义吗?

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) 

任何帮助,将不胜感激。如果我没有显示足够的代码,请告诉我。

4

1 回答 1

1

我认为您可能只是忘记/忽略了运行 io_service。

这是粗略的草图。

注意有多个设计问题:

  • 检查running()是活泼的。如果它从未运行过,你就完蛋了。如果你之前已经得到了未来的价值,你就完蛋了。
  • 无论如何,当您异步运行进程时,为什么要轮询计时器?您可以只响应完成事件。
  • 得墨忒耳法则应该适用于你的类型

Live On Coliru

#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();
}
于 2017-11-03T00:07:26.110 回答