プリエンプティブ マルチタスキングの単純なビューを想像してみてください。2 つのユーザー タスクがあり、どちらも I/O を使用したり、カーネル呼び出しを実行したりせずに常に実行されています。これら 2 つのタスクは、マルチタスク オペレーティング システムで実行できるようにするために特別なことを行う必要はありません。カーネルは通常、タイマー割り込みに基づいて、1 つのタスクを一時停止して別のタスクを実行できるようにすると単純に判断します。問題のタスクは、何かが起こったことをまったく認識していません。
ただし、ほとんどのタスクは、システムコールを介してカーネルの要求を時折行います。これが発生すると、同じユーザー コンテキストが存在しますが、CPU はそのタスクに代わってカーネル コードを実行しています。
Older Linux kernels would never allow preemption of a task while it was busy running kernel code. (Note that I/O operations always voluntarily re-schedule. I'm talking about a case where the kernel code has some CPU-intensive operation like sorting a list.)
If the system allows that task to be preempted while it is running kernel code, then we have what is called a "preemptive kernel." Such a system is immune to unpredictable delays that can be encountered during syscalls, so it might be better suited for embedded or real-time tasks.
For example, if on a particular CPU there are two tasks available, and one takes a syscall that takes 5ms to complete, and the other is an MP3 player application that needs to feed the audio pipe every 2ms, you might hear stuttering audio.
プリエンプションに反対する議論は、タスク コンテキストで呼び出される可能性のあるすべてのカーネル コードがプリエンプションに耐えられなければならないということです。そのプロセッサで他のタスクを実行できるようにします。(最近のマルチプロセッサ システムでは、すべてのカーネル コードが再入可能でなければならないため、例外ではなく規則になっているため、今日ではその議論は適切ではありません。)さらに、システム コールの不良を改善することで同じ目標を達成できる場合は、おそらくプリエンプションは不要です。
妥協点は CONFIG_PREEMPT_VOLUNTARY です。これは、カーネル内の特定のポイントでタスク切り替えを許可しますが、どこでも許可するわけではありません。カーネル コードが行き詰まる可能性のある場所が少数しかない場合、これは、複雑さを管理しやすくしながらレイテンシを削減する安価な方法です。