This is a bit of a stretch. The way cooperative systems worked is that blocking or long-running calls tended to yield. Most of the time the explicit yields therefore weren't needed, you could just wait until the next blocking call.
You could replace the cooperative system with preemption and most people wouldn't notice the difference. That's exactly what Win32 did, the programming model and APIs were largely philosophically the same.
Today's preemptive multitasking systems also sometimes call the scheduler on syscalls, effectively doing the same as those cooperative systems did. And eg. Linux has sched_yield. It's pretty common even today to see that wherever you have something close to a busy loop.
Win16 programs just called GetMessage() in a loop. If there was a message for that window proc, then that call returned and once it did, that window proc had the CPU - and nothing could preempt it. Nothing else in the system would get CPU time unless that window proc completed its activity and looped back to call GetMessage() again, or alternatively, calls yeild(). That's it. Yield() was intended to be used where the window proc needed to do something long running, thus giving other processes a chance to process their window messages.
> You could replace the cooperative system with preemption and most people wouldn't notice the difference.
Oh yes we did notice! I beta-tested several MS OSes (Win3.0, Win3.1, WfW3.11, Win95, NT3.0, Win98). The difference between the cooperative multitasking on Win16 and the preemptive multitasking on Win32 was like chalk and cheese! Before that, a single misbehaving app could hang your entire system at any time. Needed a hard reset or power cycle. At least with Win9x, it took a misbehaving driver to hang your PC. A misbehaving app would (usually) only take out itself.
> philosophically the same
Diametrically opposed. In one model, the active process voluntarily relinquishes the CPU, and until it does, nothing else will run. In the other, the scheduler pulls the CPU out from under the running thread, to switch to another thread.
You are talking down to me in your technical explanations. I know how it worked.
My point is the cooperative model was an approximation of what you get with preemption. Eventually something yields. A casual user and even many programmers would most certainly not notice a huge difference outside of extraordinary circumstances. In many instances you write code the same way. In many instances a user sees more or less the same thing.
A busy loop without a yield or a hanging program is one of those exceptional circumstances. It didn't happen even a majority of the time.
If the model were radically different, then Win32 would look way more different than Win16 than it did. But you can change the model without throwing out most APIs. If it were anything like the joke "come from" proposals, that wouldn't be the case.
You could replace the cooperative system with preemption and most people wouldn't notice the difference. That's exactly what Win32 did, the programming model and APIs were largely philosophically the same.
Today's preemptive multitasking systems also sometimes call the scheduler on syscalls, effectively doing the same as those cooperative systems did. And eg. Linux has sched_yield. It's pretty common even today to see that wherever you have something close to a busy loop.