【问题标题】:Coroutine-local variable in boostboost中的协程局部变量
【发布时间】:2015-11-29 13:52:27
【问题描述】:

我正在寻找类似于线程局部变量的东西,但是对于 boost::corotine(实际上我使用 boost:asio::spawn)。考虑以下代码:

void coroutine_work(boost::asio::yield_context yield) {
    async_foo( yield );
    some_function();
}
void some_function() {
    fprintf(log_fd, "%s Some function called", the_magic_request_id);
}

我想在初始化请求时将此the_magic_request_id 设置为某个值,这将类似于“当前请求ID”。

没有这个,我必须将the_magic_request_id 传递给每个功能和每个登录项目的模块。 some_function 只是一个例子,实际上我有很多类,它们做不同的工作,但它们都需要yield_contextthe_magic_request_id 才能创建实例。我想简化这些类的接口。

可能设置“on_sleep”和“on_resume”挂钩,这将设置一个全局变量?或者 boost::coroutine 已经为此提供了一些现成的用户机制?未在文档中找到可用的内容。

【问题讨论】:

标签: c++ boost boost-asio boost-context boost-coroutine


【解决方案1】:

您可以使用 boost.fiber(用户级线程,boost::fibers::asio::yield_context),而不是使用 boost.coroutine (boost::asio::yield_context)。 boost.fiber 支持 fiber_specific_ptr(相当于 boost.thread 的 thread_specific_ptr)。

文档:http://olk.github.io/libs/fiber/doc/html/index.html

【讨论】:

【解决方案2】:

您可以使用绑定的函数对象来包含状态。

事实上,绑定函数对象可以优雅地表示为带有捕获的 lambda。确保捕获是按值进行的(这样您就不会意外地与其他实例共享状态),如果不是,它们引用的对象的生存时间足够长。

例如

extern std::ostream& log_stream; // for exposition only

struct coroutine_work {

    boost::uuids::uuid the_magic_request_id = boost::uuids::random_generator{}();

    void operator()(boost::asio::yield_context yield) {
        async_foo(yield);
        some_function();
    }

    void some_function() const {
        log_stream << the_magic_request_id << " Some function called\n";
    }
}

或者:

static void some_function(boost::uuids::uuid const& reqid) const {
    log_stream << reqid << " Some function called\n";
}

struct coroutine_work {
    boost::uuids::uuid the_magic_request_id = boost::uuids::random_generator{}();

    void operator()(boost::asio::yield_context yield) {
        async_foo(yield);
        some_function(the_magic_request_id);
    }
}

或者转化为lambda形式:

static void some_function(boost::uuids::uuid const& reqid) const {
    log_stream << reqid << " Some function called\n";
}

// somewhere else: 
{
    boost::uuids::uuid the_magic_request_id = boost::uuids::random_generator{}();

    auto coroutine_work = [the_magic_request_id](boost::asio::yield_context yield) {
        async_foo(yield);
        some_function(the_magic_request_id);
    }
}

【讨论】:

  • 感谢您的回答。这并没有消除将the_magic_request_id 传递给每个函数和每个类的要求。 some_function 只是一个例子,实际上我有很多类,它们做不同的工作,但它们都需要yield_contextthe_magic_request_id 才能创建实例。
  • AFAICT Boost Coroutine 中的 stack_context 是 pull_coroutine 的一部分(asio 中的 yield_context 是指事物的推送方面)。因此,似乎很难以可靠的方式访问堆栈上下文。
  • 我有两种方法正在萌芽:Live On Coliru。第一个是您建议的全球地图(使用Associating arbitrary data with heterogeneous shared_ptr instances 技术)。另一个试图从协程中破解/撬动 SS 寄存器。但令我惊讶的是,堆栈段寄存器似乎获得了非常可靠的 - 固定值。我希望 stackful 协程会有可区分的堆栈段...
  • 有趣的是,SS 寄存器在使用实际线程时显然甚至没有变化:Live On Coliru。同时,您可以看到注册表方法有效,但没有yield_context 就没有“静默”密码...
  • 对它的工作原理感兴趣吗?根据头文件,coro_(callee_type)是一个私有字段。另外最好不要到处传递 yield_context 引用(也许通过在协程输入上设置指向全局变量的指针)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-16
  • 1970-01-01
  • 2010-09-24
  • 2014-03-03
  • 1970-01-01
  • 2017-10-20
相关资源
最近更新 更多