Chaining Boost Process on_exit completion handlers

huangapple go评论70阅读模式
英文:

Chaining Boost Process on_exit completion handlers

问题

I'm trying to restart the same process right after the old one exits, but after few executions my program crashes. Valgrind is reporting invalid reads and writes related to the handler, but I'm having no luck with getting closer to a fix. The sample code shows only one process, but my goal is to have a few of these processes that restart themselves running at the same time.

std::function<void(int, const std::error_code&)> on_exit;
on_exit = [this, &on_exit](int exit, const std::error_code& ec_in) {
    // error handling
    client.wait();
    client = bp::child(path_to_client, io_context, bp::on_exit=on_exit);
};
client = bp::child(path_to_client, io_context, bp::on_exit=on_exit);
io_context.run();

The client, path_to_client, and io_context are all members of a class.

Removing the call to launch the new process inside the lambda fixes the valgrind errors.

英文:

I'm trying to restart the same process right after the old one exits, but after few executions my program crashes. Valgrind is reporting invalid reads and writes related to the handler, but I'm having no luck with getting closer to a fix. The sample code shows only one process, but my goal is to have a few of these processes that restart themselves running at the same time.

std::function&lt;void(int, const std::error_code&amp;)&gt; on_exit;
on_exit = [this, &amp;on_exit](int exit, const std::error_code&amp; ec_in) {
    // error handling
    client.wait();
    client = bp::child(path_to_client, io_context, bp::on_exit=on_exit);
};
client = bp::child(path_to_client, io_context, bp::on_exit=on_exit);
io_context.run();

The client, path_to_client, and io_context are all members of a class.

Removing the call to launch the new process inside the lambda fixes the valgrind errors.

答案1

得分: 0

on_exit 是一个本地函数,但你通过引用捕获它。通过使用成员变量如 client 等方式使其存活足够长来修复它。

以下是一个自包含的演示程序:

#include <boost/process.hpp>
#include <iostream>
namespace bp = boost::process;

struct ProgramX {
    boost::asio::io_context                   io_context;
    bp::child                                 client;
    unsigned                                  remaining = 0;

    std::function<void(int, std::error_code)> on_exit = [this](int exit, std::error_code ec) {
        client.wait();

        std::cout << "exit code " << exit << " (" << ec.message() << ")" << std::endl;
        // 错误处理...

        if (--remaining)
            launch();
    };

    void launch() {
        boost::filesystem::path  path_to_client = "/bin/sleep";
        std::vector<std::string> args           = {"1"};
        client = bp::child(path_to_client, args, io_context, bp::on_exit = on_exit);
    }

    void foo(unsigned how_many_runs) {
        remaining = how_many_runs;
        launch();
        io_context.run();
    }
};

int main() {
    ProgramX x;
    x.foo(5);
}

更新:早期 Boost 版本中的错误

在尝试在线操作时,我注意到... 它的表现不如预期。

在我的本地机器上,如下所示:

Chaining Boost Process on_exit completion handlers

所以很有可能你也需要尽早升级到 Boost 1.82.0。


【注】:请注意,两者都标记为 108200,但你可以看到我只切换了进程子模块的发布标签。
1: https://i.stack.imgur.com/rMCoP.gif

英文:

on_exit is a local function, but you capture it by reference. Fix it by making it live long enough, e.g. by using a member variable like client instead.

Here's a self-contained demo program:

#include &lt;boost/process.hpp&gt;
#include &lt;iostream&gt;
namespace bp = boost::process;

struct ProgramX {
    boost::asio::io_context                   io_context;
    bp::child                                 client;
    unsigned                                  remaining = 0;

    std::function&lt;void(int, std::error_code)&gt; on_exit = [this](int exit, std::error_code ec) {
        client.wait();

        std::cout &lt;&lt; &quot;exit code &quot; &lt;&lt; exit &lt;&lt; &quot; (&quot; &lt;&lt; ec.message() &lt;&lt; &quot;)&quot; &lt;&lt; std::endl;
        // error handling...

        if (--remaining)
            launch();
    };

    void launch() {
        boost::filesystem::path  path_to_client = &quot;/bin/sleep&quot;;
        std::vector&lt;std::string&gt; args           = {&quot;1&quot;};
        client = bp::child(path_to_client, args, io_context, bp::on_exit = on_exit);
    }

    void foo(unsigned how_many_runs) {
        remaining = how_many_runs;
        launch();
        io_context.run();
    }
};

int main() {
    ProgramX x;
    x.foo(5);
}

UPDATE: Bugs in Earlier Boost Versions

When trying things online, I noticed that... it didn't work as expected.

Here's a side-by-side on my local machine¹:

Chaining Boost Process on_exit completion handlers

So in all likelihood, you (also) need to update to Boost 1.82.0 sooner rather than later.


¹ note both say 108200 but you can see me switching the release tag for just the process submodule

huangapple
  • 本文由 发表于 2023年4月20日 03:57:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76058363.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定