Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7170403
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 28, 20262026-05-28T15:12:21+00:00 2026-05-28T15:12:21+00:00

Background: I’m trying to figure out how to implement continuations/coroutines/generators (whatever the following is

  • 0

Background: I’m trying to figure out how to implement continuations/coroutines/generators (whatever the following is called) by posing this toy problem. The environment is C++11 on gcc 4.6 and linux 3.0 x86_64. Non-portable is fine but using an external library (boost.coroutine, COROUTINE, etc) is not allowed. I think longjmp(3) and/or makecontext(2) and friends may help but not sure.

Description:

The following toy parser is supposed to parse sequences of as and bs of equal length. ie

((a+)(b+))+

such that the length of the second bracketed production equals the third.

When it finds a production (eg aaabbb) it outputs the number of as it finds (eg 3).

Code:

#include <stdlib.h>
#include <iostream>
using namespace std;

const char* s;

void yield()
{
        // TODO: no data, return from produce
        abort();
}

void advance()
{
        s++;
        if (*s == 0)
                yield();
}

void consume()
{
        while (true)
        {
                int i = 0;

                while (*s == 'a')
                {
                        i++;
                        advance();
                }

                cout << i << " ";

                while (i-- > 0)
                {
                    if (*s != 'b')
                        abort();
                    advance();
                }
        }
}

void produce(const char* s_)
{
        s = s_;

        // TODO: data available, continue into consume()
        consume();
}

int main()
{
        produce("aaab");
        produce("bba");
        produce("baa");
        produce("aabbb");
        produce("b");

        // should print: 3 1 4

        return 0;
}

Problem:

As you can see the state of the consume call stack must be saved when yield is called and then produce returns. When produce is called again, consume must be restarted by returning from yield. The challenge would be to modify the way produce calls consume, and implement yield so they function as intended.

(Obviously reimplementing consume so that it saves and rebuilds its state defeats the purpose of the exercise.)

I think what needs to be done is something like the example on the bottom of the makecontext man page: http://www.kernel.org/doc/man-pages/online/pages/man3/makecontext.3.html, but its not clear how to translate it onto this problem. (and I need sleep)

Solution:

(Thanks to Chris Dodd for design)

#include <stdlib.h>
#include <iostream>
#include <ucontext.h>
using namespace std;

const char* s;
ucontext_t main_context, consume_context;

void yield()
{
    swapcontext(&consume_context, &main_context);
}

void advance()
{
    s++;
    if (*s == 0)
            yield();
}

void consume()
{
    while (true)
    {
            int i = 0;

            while (*s == 'a')
            {
                    i++;
                    advance();
            }

            cout << i << " ";

            while (i-- > 0)
            {
                    advance();
            }
    }
}

void produce(const char* s_)
{
    s = s_;

    swapcontext(&main_context, &consume_context);
}

int main()
{
    char consume_stack[4096];

    getcontext(&consume_context);
    consume_context.uc_stack.ss_sp = consume_stack;
    consume_context.uc_stack.ss_size = sizeof(consume_stack);
    makecontext(&consume_context, consume, 0);

    produce("aaab");
    produce("bba");
    produce("baa");
    produce("aabbb");
    produce("b");

    // should print: 3 1 4

    return 0;
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-28T15:12:22+00:00Added an answer on May 28, 2026 at 3:12 pm

    Its fairly straight-forward to use makecontext/swapcontext for this — you use makecontext to create a new coroutine context and swapcontext to swap between them. In you case, you need one additional coroutine to run the consume infinite loop, and you run main and produce in the main context.

    So main should call getcontext+makecontext to create a new context that will run the consume loop:

    getcontext(&consume_ctxt);
    // set up stack in consume_context
    makecontext(&consume_ctxt, consume, 0);
    

    and then produce will switch to it instead of calling consume directly:

    void produce(const char* s_)
    {
        s = s_; 
        swapcontext(&main_ctxt, &consume_ctxt);
    }
    

    and finally yield just calls swapcontext(&consume_ctxt, &main_ctxt); to switch back to the main context (which will continue in produce and immediately return).

    Note that since consume is an infinite loop, you don’t need to worry too much about what happens when it returns (so the link will never be used)

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Background Information I'm trying to build the GAUL library according to this Instructions .
Background : I'm trying to convert some JavaScript code which uses the the Crossfilter
Background info I am trying to upgrade a custom CMS to support the HTML5
Background I have an installation of VisualSVN on a server. under this, I have
Background Hi All, I'm trying to use Boost::MPI, at the moment I'm just trying
Background info: Me and a couple of friends are building this platform game in
Background: I have a website where people can store transactions. As part of this
Background I once wrote this method: private <T> SortedSet<T> createSortedSet() { return new TreeSet<T>();
Background: While reading about the smart pointers I came across the following sample implementation
Background I am trying to create a copy of a business object I have

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.