I have been tasked in a class to create a user level thread library in C. I was wondering if anyone could give me a list of things to read up on to accomplish this. I have a good idea as to where to start, but any resources on user level threads and some applicable aspects of the C language that might help would be extremely valuable.
I am very unclear as to how I would implement a scheduler for such. Assume that I have a pretty good understanding of the C language and some of its more helpful library functions.
In general, user-level threads can be implemented using one of four models. All models maps user-level threads to kernel-level threads. A kernel thread is similar to a process in a non-threaded (single-threaded) system. The kernel thread is the unit of execution that is scheduled by the kernel to execute on the CPU.
User-level threads can be created in different ways. One of them is through context switching . There will be a single process and we change the context in a round-robin fashion. We change the context to some different thread after every short time interval.
I’ve done this for a homework assignment without writing any assembler at all. The thread switch mechanism was setjmp
/longjmp
. What this involved was allocating memory for each thread’s stack, then very carefully massaging the values in the jmp_buff
so execution jumps to the next thread’s stack.
See also Russ Cox’s pretty readable libtask.
Edit in response to OP’s comment: In deciding when to switch threads there are two main directions: preemptive & cooperative. In the preemptive model, you’ll have something like a timer signal that causes execution flow to jump to a central dispatcher thread, which chooses the next thread to run. In a cooperative model, threads “yield” to each other, either explicitly (e.g., by calling a yield()
function you’ll provide) or implicitly (e.g., requesting a lock held by another thread).
Take a look at the API of libtask for an example of the cooperative model, particularly the description of the function taskyield()
. That’s the explicit yield I mentioned. There are also the non-blocking I/O functions which include an implicit yield—the current “task” is put on hold until the I/O completes, but the other tasks get their chance to run.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With