Where the processes are more tightly coupled, the developer must wrestle with whatever facilities are available for interprocess communication. These facilities are seldom simple and never fully portable.
Some environments, such as MS-DOS or some embedded systems, don't support multiple processes. In that case you must resort to some form of multithreading.
Instead of various mechanisms of interprocess communication, true threads use various mechanisms of interthread communication, which may be simpler or incur less overhead. However they are also more subtle. Because different threads may access the same memory at unpredictable times, it is easy for them to interfere with each other in ways that are difficult to reproduce or debug.
With true threads, you must allocate a chunk of memory for each thread to serve as a working stack. Typically, at any one time, much of that memory is unused, depending on where the threads are in their respective calling chains. The resulting waste of memory can be considerable, especially for large numbers of threads.
When the runtime system jumps from thread to thread, it must also jump from stack to stack. There is no way to do so in Standard C or C++. Unless you use a language such as Java that supports multithreading directly, true threads are inherently non-portable.
Because Cheap Threads is open software, you can tinker with it to suit your needs, subject to the terms of the GNU Lesser General Public License. For example, you might eliminate features you don't use, in order to reduce overhead. You might convert it to C++ or K&R C, or add a new feature. I'd like to think you'll never need to debug it, but you can if you have to.
Because Cheap Threads is entirely synchronous, it avoids the subtle dangers surrounding true threads when two or more of them access the same resources. You don't have to use semaphores, mutexes, or any of their kindred.
Cheap Threads does not allocate a separate stack for each thread, and is therefore sparing in its use of memory. As it jumps from thread to thread, it reuses the same stack used by the other threads. Each thread is responsible for saving its own state between invocations, by whatever means necessary.
It is always risky to make predictions about performance without doing the appropriate benchmarks. Nevertheless it is likely that Cheap Threads will incur less overhead than other forms of multitasking. The use of multiple processes involves many context switches, which typically are relatively expensive operations. The task switching used in true multithreading may or may not incur much overhead, but the use of mutexes and the like incurs overhead that doesn't apply to Cheap Threads.
Finally, Cheap Threads is available at no charge. You can't get much cheaper than that.
Now for the drawbacks.
As noted earlier, a long and complicated task may need to be broken up into smaller pieces. This style of coding is likely to feel awkward and unnatural. It also incurs overhead of its own, as the thread repeatedly navigates in and out of whatever it's doing.
Because the scheduler never interrupts a running task, it is possible for a long-running thread to use up more than its fair share of the CPU, or to get trapped in an endless loop. Several mechanisms give the developer some control over the scheduling, but they cannot promise more than an approximate balance among the threads.
For that purpose, Cheap Threads has nothing to offer. If one thread waits for IO, they all wait.
On the other hand, you may be able to implement non-blocking IO by other means, using (for example) calls to low-level interrupt routines. In that case Cheap Threads may provide a useful way to organize whatever the application does while it waits for the IO to complete.