A limited form of multi-threading that requires a thread's cooperation in yielding the CPU. A thread switch cannot take place in response to an external event. This means that, in many implementations,
CooperativeThreading is useless for real-time work, because real-time response means that a low priority thread can be suspended to dispatch a thread in order to service the external event.
Frequently implemented with
CoRoutines, but not identical to them.
However, despite popular belief,
CooperativeThreading can take advantage of multiple processors. As many cooperative threads run as there are processors, and they stay on their processor until they yield. But of course, synchronization requires real locks; the cooperatively threaded software can no longer assume that as long as a thread does not yield, it owns a critical section.
This is the
AchillesHeel of cooperative threading: programmers get lazy and start making assumptions about the concurrency. Those assumptions not only break if the software has to be ported to preemptive threading, or SMP, but they can break even under the single-processor cooperative model. When software becomes sufficiently complex, it's hard to be sure that some function you are calling does not contain an internal yield somewhere! If you assume that a the function call did not yield, but it in fact did, then the state of the world may have been changed by another thread.
If you ever have to deal with cooperative threading package, it's best to treat it like preemptive threading and use proper synchronization everywhere.
It's noteworthy that traditional Unix kernels are cooperative; when you are running kernel code, another process won't be dispatched, unless you explicitly suspend by adding yourself to a wait queue and calling the scheduler. Only user space code can be preempted! Linux works like this too. When SMP was introduced to Unix kernels, it was done by extending the semantics of cooperative threading to multiple processors. Once you get that right, because you have to do real locking to make it work, you can start adding real preemption while you are at it. This is what the relatively recent (2003) preemptive patches for Linux are all about.
In Unix kernels there can arise some pretty tricky cooperative threading issues. For example, code that looks like it obviously does not yield may do so anyway! Why? Because it hits a page fault accessing some user space data, for instance, and the handle for that page fault will suspend the process until the data is swapped in. Oops, a hidden yield in a simple memory access instruction! This is why explicit interfaces are used to validate and copy user space data. Once it is copied into kernel space you can work with it without the risk of interruption.
Linux, and other Unix varieties, have have pre-emptive kernels for quite some time now.
CategoryOperatingSystem
CategoryRealTime CategoryConcurrency