init init - 3 months ago 31
C Question

How are user-level threads scheduled/created, and how are kernel level threads created?

Apologies if this question is stupid. I tried to find an answer online for quite some time, but couldn't and hence I'm asking here. I am learning threads, and I've been going through this link and this Linux Plumbers Conference 2013 videoabout kernel level and user level threads, and as far as I understood, using pthreads create threads in the userspace, and the kernel is not aware about this and view it as a single process only, unaware of how many threads are inside. In such a case,


  • who decides the scheduling of these user threads during the timeslice the process gets, as the kernel sees it as a single process and is unaware of the threads, and how is the scheduling done?

  • If pthreads create user level threads, how are kernel level or OS threads created from user space programs, if required?

  • According to the above link, it says Operating Systems kernel provides system call to create and manage threads. So does a
    clone()
    system call creates a kernel level thread or user level thread?


    • If it creates a kernel level thread, then
      strace
      of a simple pthreads program also shows using clone() while executing, but then why would it be considered user level thread?

    • If it doesn't create a kernel level thread, then how are kernel threads created from userspace programs?


  • According to the link, it says "It require a full thread control block (TCB) for each thread to maintain information about threads. As a result there is significant overhead and increased in kernel complexity.", so in kernel level threads, only the heap is shared, and the rest all are individual to the thread?



Edit:

I was asking about the user-level thread creation, and it's scheduling because here, there is a reference to Many to One Model where many user level threads are mapped to one Kernel-level thread, and Thread management is done in user space by the thread library. I've been only seeing references to using pthreads, but unsure if it creates user-level or kernel-level threads.

Answer

User level threads are usually coroutines, in one form or another. Switch context between flows of execution in user mode, with no kernel involvement. From kernel POV, is all one thread. What the thread actually does is controlled in the user mode, and the user mode can suspend, switch, resume logical flows of executions (ie. coroutines). It all happens during the quanta scheduled for the actual thread. Kernel can, and will unceremoniously interrupt the actual thread (kernel thread) and give control of the processor to another thread.

User mode coroutines require cooperative multitasking. User mode threads must periodically relinquish control to other user mode threads (basically the execution changes context to the new user mode thread, without the kernel thread ever noticing anything). Usually what happens is that the code knows a whole lot better when it wants to release control that the kernel would. A poorly coded coroutine can steal control and starve all other coroutines.

The historical implementation used setcontext but that is now deprecated. Boost.context offers a replacement for it, but is not fully portable:

Boost.Context is a foundational library that provides a sort of cooperative multitasking on a single thread. By providing an abstraction of the current execution state in the current thread, including the stack (with local variables) and stack pointer, all registers and CPU flags, and the instruction pointer, a execution_context represents a specific point in the application's execution path.

Not surprisingly, Boost.coroutine is based on Boost.context.

Windows provided Fibers. .Net runtime has Tasks and async/await.