2

Im searching for something similar to thread-local variables, but for boost::corotine (actually i use boost:asio::spawn). Consider following code:

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

I want to set this the_magic_request_id to some value when request is initialized, which will serve like "current request id".

Without this, i must pass the_magic_request_id to every function and every module which do logging in project. some_function is just an example, actually i have many classes, they do different work, but all of them require yield_context and the_magic_request_id in order to create an instance. I want to simplify interfaces for these classes.

Probably its possible to set "on_sleep" and "on_resume" hooks, which will set a global variable? Or boost::coroutine already have some ready-to-user mechanics for this? Did not found something usable in the docs.

Galimov Albert
  • 7,269
  • 1
  • 24
  • 50

2 Answers2

3

Instead of using boost.coroutine (boost::asio::yield_context) you could use boost.fiber (user-land threads,boost::fibers::asio::yield_context). boost.fiber supports fiber_specific_ptr (eq. to boost.thread's thread_specific_ptr).

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

olk
  • 372
  • 1
  • 3
  • Blimey. I learned something new here. See also: ["_The author of Boost.Fiber tells me that as of January 2015 the recommended changes from the community review are complete, and apart from documentation improvements Fiber is considered ready for inclusion into official Boost. If this is indeed the case, then Fiber is probably the best solution before official C++ 17 language support for final resumable functions appears in compilers._"](http://stackoverflow.com/a/27876250/85371) – sehe Sep 04 '15 at 11:24
  • @olk This is very interesting, but i want to find possibilities in my current project. – Galimov Albert Sep 04 '15 at 12:33
  • @sehe: resumable function != fibers (or stackfull coroutines) - resumable functions as proposed by MS (Gor) can not suspend from nested call stack, e.g. you can not suspend the resumable function from within a sub-routine called inside the resumable function. The only exception is that all functions in the chain are resumable functions too => resumable functions are virulent in this case. – olk Sep 04 '15 at 13:30
0

You can use a bound function object to contain the state.

In fact that bound function object can be elegantly expressed as lambda with captures. Make sure that captures are by value (so you don't accidentally share the state with other instances) and if not, the objects they refer to live long enough.

E.g.

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

Alternatively:

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

Or transformed into lambda form:

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);
    }
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks for you answer. This does not eliminate requirement to pass `the_magic_request_id` into every function and every class. `some_function` is just an example, actually i have many classes, they do different work, but all of them require `yield_context` and `the_magic_request_id` in order to create an instance. – Galimov Albert Sep 03 '15 at 16:48
  • AFAICT the stack_context in Boost Coroutine is part of the pull_coroutine (and the yield_context in asio refers to the push side of things). Therefore it seems hard to get to the stack-context in a dependable manner. – sehe Sep 03 '15 at 22:59
  • I have two approaches budding here: **[Live On Coliru](http://coliru.stacked-crooked.com/a/6c0a6c8a09a62cc6)**. The first is the global map that you suggested (using the [Associating arbitrary data with heterogeneous shared_ptr instances](http://www.boost.org/doc/libs/1_57_0/libs/smart_ptr/sp_techniques.html#extra_data) technique). The other tries to hack/pry the SS register from the coroutine. But to my surprise the stack segment register appears to get very reliable - fixed - values. I hope _stackful_ coroutines would have distinguishable stack segments... – sehe Sep 03 '15 at 23:02
  • Interestingly the SS register apparently doesn't even vary when using actual threads: **[Live On Coliru](http://coliru.stacked-crooked.com/a/e62b4701297cc93e)**. Meanwhile you can see the registry approach working, but no "silent" passthry without `yield_context`... – sehe Sep 03 '15 at 23:12
  • interesting how it works? According to header file, coro_ (callee_type) is a private field. Also it would be great not to pass yield_context reference everywhere (maybe by setting pointer to global variable on coroutine enter) – Galimov Albert Sep 04 '15 at 12:30
  • > (maybe by setting pointer to global variable on coroutine enter) - I hope you mean thread-local. Also, why do you want that? Are you sure you cannot fix it by making the functors contain a member reference to the coro/yield context instead? [ Why compromise design and do it on the undocumented edges of complicated platform-specific library features... ] – sehe Sep 04 '15 at 12:41