I'm trying to implement a thread switcher in c using the ucontext.h
library.
I am doing this using a queue system where the next thread to run is at the front of the queue. When a thread pauses; I pop the node at the top of the queue, switch the running context with the one stored in that node, and push the node back onto the queue. This looks something like this:
I have a test case where I place two threads in the queue. Each thread prints its ID before pausing. I expect the two to alternate. Instead the firs thread runs to completion and the second does not run. I've narrowed this problem down to the way I swap the threads:
QManager.c
void pause () {
struct ThreadNode* t= QManagerPop(Q);
swapcontext(t->context, t->context);
QManagerPush(t);
}
Seemingly; this does not switch the running context with the one stored in `t->context'.
I am looking for a way to do this; place the current context in a variable `t->context' while at the same time resuming the context that was stored in that variable.
I tried the following based on some information I found online
QManager.c
void switch (ucontext_t* c) {
volatile int isSwap = 0;
int isGet = getcontext(c);
if (!isSwap && isGet ==0) {
isSwap = 1;
setcontext(c);
}
}
void pause () {
struct ThreadNode* t= QManagerPop(Q);
switch(t->context);
QManagerPush(t);
}
This produces the same behaviour (with an additional segfault at the end).
Is there some way to do what I am looking to do? Maybe something with a temp variable? How would I deal with this variable when the context switches?
swapcontext
context can't be the same pointer since the parameters arerestrict
.Instead of allocating and deallocating all those threads, you could work with thread ids, which is to say indexes into an array of structures that contains the context and other data to a thread.
Then, switching context context becomes
and
pause
becomesActually, if all the threads are in an array, then we don't need queue. We just need to find the next thread in the array.
This code comes from this earlier answer of mine, where you can see these functions used.
Note these fixes:
void f()
doesn't mean the function takes no argument.Note these renames:
Q
⇒q
.It's not a module name or constant.
QManagerPush
⇒QManagerEnqueue
andQManagerPop
⇒QManagerDequeue
.Push and pop are stack operations, not queue operations.
pause
⇒yield
.yield
orcede
are more appropriate names.