boost context class

5k views Asked by At

I found boost has a class called context which is used for context switching, right?

I try to Google it but did not found any document or example. I am just wondering if anyone can provide some information.

3

There are 3 answers

6
wjl On BEST ANSWER

Boost::Context is an official part of Boost in version 1.51.0 and up. See http://www.boost.org/doc/libs/1_51_0/libs/context/doc/html/index.html for information about it. Unfortunately the documentation is slightly different than the implementation, and some things have changed in SVN, so you'll need to read the header files a little bit.

Here is an example I wrote the other day showing Boost::Context to make simple coroutines using Boost 1.51.0+latest SVN:

#include <array>
#include <functional>

#include <boost/context/all.hpp>

class Coroutine {
    public:
    Coroutine() :
        my_context(boost::context::make_fcontext(
            stack.data() + stack.size(),
            stack.size(),
            Coroutine::dispatch
        ))
    {}
    virtual ~Coroutine() {}

    void operator()() {
        boost::context::jump_fcontext(&yield_context, my_context, reinterpret_cast<intptr_t>(this));
    }

    protected:
    void yield() {
        boost::context::jump_fcontext(my_context, &yield_context, 0);
    }

    virtual void call() = 0;

    private:
    static void dispatch(intptr_t coroutine_ptr) {
        Coroutine *coroutine = reinterpret_cast<Coroutine *>(coroutine_ptr);
        coroutine->call();
        while (true) coroutine->yield();
    }

    private:
    boost::context::fcontext_t *my_context;
    boost::context::fcontext_t yield_context;
    std::array<intptr_t, 64*1024> stack;
};

struct A : public Coroutine {
    void call() {
        std::cerr << "A went to the store one day.\n";
        yield();
        std::cerr << "A was looking for groceries.\n";
        yield();
        std::cerr << "A finally found what she was looking for.\n";
    }
};

struct B : public Coroutine {
    void call() {
        std::cerr << "B went to the store one day.\n";
        yield();
        std::cerr << "B was looking for replacement tires.\n";
        yield();
        std::cerr << "B didn't find anything at all.\n";
        yield();
        std::cerr << "B went to another store.\n";
        yield();
        std::cerr << "B got the tires installed there.\n";
    }
};

struct C : public Coroutine {
    void call() {
        std::cerr << "C went to the store one day.\n";
        yield();
        std::cerr << "C was looking for USB drives.\n";
        yield();
        std::cerr << "C found several with competitive pricing.\n";
        yield();
        std::cerr << "C couldn't decide which to buy, so gave up.\n";
    }
};


int main() {
    std::cerr << "So, this is what happened.\n";
    A a;
    B b;
    C c;
    for (size_t i=0; i<10; ++i) {
        a();
        b();
        c();
    }
    std::cerr << "Then it all was done.\n";
}

Then compiling and running looks like this:

$ g++ -std=c++11 -o coroutines coroutines.c++ -lboost_context
$ ./coroutines
So, this is what happened.
A went to the store one day.
B went to the store one day.
C went to the store one day.
A was looking for groceries.
B was looking for replacement tires.
C was looking for USB drives.
A finally found what she was looking for.
B didn't find anything at all.
C found several with competitive pricing.
B went to another store.
C couldn't decide which to buy, so gave up.
B got the tires installed there.
Then it all was done.
0
z3moon On

Thank you wjl for your example code. It helped me understand how boost context works and how boost coroutine is implemented by means of boost context. But your code didn't work as it was, so I modified it to be compiled on Windows. (didn't check if it works on Linux though)

#include <iostream>
#include <array>
#include <boost/context/all.hpp>

class Coroutine {
public:
  Coroutine() :
    my_context(boost::context::make_fcontext(
    stack.data() + stack.size(),
    stack.size(),
    Coroutine::dispatch
    ))
  {}
  virtual ~Coroutine() {}

  void operator()() {
    boost::context::jump_fcontext(&yield_context, my_context, reinterpret_cast<intptr_t>(this));
  }

protected:
  void yield() {
    boost::context::jump_fcontext(&my_context, yield_context, 0);
  }

  virtual void call() = 0;

private:
  static void dispatch(intptr_t coroutine_ptr) {
    Coroutine *coroutine = reinterpret_cast<Coroutine *>(coroutine_ptr);
    coroutine->call();
    while (true) coroutine->yield();
  }

private:
  boost::context::fcontext_t my_context;
  boost::context::fcontext_t yield_context;
  std::array<intptr_t, 64 * 1024> stack;
};

struct A : public Coroutine {
  void call() {
    std::cerr << "A went to the store one day.\n";
    yield();
    std::cerr << "A was looking for groceries.\n";
    yield();
    std::cerr << "A finally found what she was looking for.\n";
  }
};

struct B : public Coroutine {
  void call() {
    std::cerr << "B went to the store one day.\n";
    yield();
    std::cerr << "B was looking for replacement tires.\n";
    yield();
    std::cerr << "B didn't find anything at all.\n";
    yield();
    std::cerr << "B went to another store.\n";
    yield();
    std::cerr << "B got the tires installed there.\n";
  }
};

struct C : public Coroutine {
  void call() {
    std::cerr << "C went to the store one day.\n";
    yield();
    std::cerr << "C was looking for USB drives.\n";
    yield();
    std::cerr << "C found several with competitive pricing.\n";
    yield();
    std::cerr << "C couldn't decide which to buy, so gave up.\n";
  }
};

int main() {
  std::cerr << "So, this is what happened.\n";
  A a;
  B b;
  C c;
  for (size_t i = 0; i < 10; ++i) {
    a();
    b();
    c();
  }
  std::cerr << "Then it all was done.\n";
}
2
ingoem On

The boost-coroutine archive on the author's website contains some basic docs and examples for both coroutine, which builds on context, and context itself. You'll also find a fiber package on that website, which might be interesting at least as another use case.