Galimov Albert
Galimov Albert

Reputation: 7357

Coroutine-local variable in boost

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.

Upvotes: 2

Views: 1305

Answers (2)

olk
olk

Reputation: 400

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

Upvotes: 3

sehe
sehe

Reputation: 393769

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

Upvotes: 0

Related Questions