Coroutine implementation in c++

I am trying to implement coroutines (had to reinvent the wheel as part of my project) in c++. Every coroutine is an instance of a workpackage class and stored in a packagequeue. When a workpackage(coroutine) is being executed, it is removed from the queue. Now when i call the yeild function inside this workpackage, it should jump to another workpackage in the packagequeue. This is what i am trying to do
1
2
3
4
5
myworkpackage(){
//do some stuff
yield()
// do remaing stuff
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
yield(){
    Get the context of workpackage that called yield() // Every workpackage has its own context. I dont know how to do that because workpackage is not in the packagequeue anymore and i //cant access its data members.
if (there is another package in the waitingqueue){ // Two queues for every thread i.e. waitngqueue and packagequeue
     Get its context
      Add the workpackage to the waitingqueue.
      jump_context(oldpackage, newpackage) // switching the context here
      }
     else {
         Add the workpackage to the waitingqueue.
         }
        If(packagequeue is not empty)
          grab ane execute another workpackage
        else
        steal the packe from another thread queue and execute it
}


Considering full scenario, does it make sense what i am trying to do or is there a better way to accomplish it??
Last edited on
Is there any reason not to use Boost.Coroutine?
I am writing a library for real time systems and its bare metal implementation which involves thread management and scheduling. I am not allowed to use any library what so ever for that purpose. However i am using lowest level functions (make_fcontext and jump_fcontext) for switching context between coroutines, from boost::context but and do not depend on boost
Last edited on
It seems to me like the correct implementation would be
1
2
3
4
void yield(){
    work_queue.push(get_current_context());
    jump_fcontext(work_queue.pop());
}
Note that work_queue can be implemented as a fixed-length circular buffer. You only need to resize its capacity when coroutines are created or destroyed.
Last edited on
Both package_queue and waiting_queue are implemented as fix length circular buffers. How is it possible to get the context of coroutine keeping in mind that its not in package_queue because when i pop the coroutine from queue for execution, queue indexes are getting updated.(I have to resize queue at pop because other threads might steal work from it)
Why do you have two queues? What do they contain?
I am emulating physical cores of real system via pthreads. Each Pthread(Core) has two queues. One is where normal "running" coroutines are stored(In case a coroutine creates more coroutines) and other is where i want to store waiting coroutines(which got yield). Normally when a core's own queue is empty it steals from the other core queue. When yield is called, core will continue executing those packages first that are in its waitng_queue(from previous yield calls). If its empty then execute coroutines in its package_queue otherwise steal from other cores
Last edited on
Each Pthread(Core) has two queues. One is where normal "running" coroutines are stored(In case a coroutine creates more coroutines)
What do you mean? As I understand coroutines, they have only two states:
1. Running: the coroutine has accepted the yield() from a different coroutine and has not yet yielded.
2. Suspended: the coroutine has yielded to a different coroutine, or has yet to be started for the first time.
A single thread can't be running more than a single coroutine at any given time. Even if a coroutine creates more coroutines, those coroutines must be in the suspended state until the coroutine that's currently running yields to them.
Why would you need a queue to store the coroutines that a single thread is currently running, when they can't ever be more than one?
Last edited on
Topic archived. No new replies allowed.