単一のプロセス (または実行のスレッド) が協調マルチタスクを使用する特定のシナリオでは、Windows のファイバーや POSIX setcontext ファミリーの関数などを使用できます。ここではファイバーという用語を使用します。
基本的に、あるファイバーが作業のチャンクの実行を終了し、自発的に他のファイバーの実行を許可したい場合 (したがって「協調」という用語)、他のファイバーのコンテキストに手動で切り替えるか、より一般的には何らかの yield() を実行します。 scheduler() 呼び出しがスケジューラのコンテキストにジャンプすると、スケジューラは実行する新しいファイバーを見つけて、そのファイバーのコンテキストに切り替えます。
ここでのコンテキストとは何を意味するのでしょうか? 基本的にスタックとレジスタ。スタックについて魔法は何もありません。それは、スタック ポインタがたまたま指し示すメモリのブロックにすぎません。プログラムカウンターについても魔法はなく、次に実行する命令を指すだけです。コンテキストを切り替えると、現在のレジスタがどこかに保存され、スタック ポインタが別のメモリ チャンクに変更され、プログラム カウンタが別の命令ストリームに更新され、そのコンテキストの保存されたレジスタが CPU にコピーされ、ジャンプが実行されます。バム、あなたは今、別のスタックで別の命令を実行しています。多くの場合、コンテキスト スイッチ コードは、現在のスタックを変更しないか、変更を元に戻す方法で呼び出されるアセンブリで記述されます。どちらの場合も、スタックまたはレジスタにトレースを残さないため、コードの実行が再開されたときに、何が起こったかわかりません。(繰り返しになりますが、テーマ: メソッド呼び出しはレジスタをいじったり、引数をスタックにプッシュしたり、スタック ポインターを移動したりすると想定していますが、それは単なる C 呼び出し規則です。メソッド呼び出しは、それ自体の痕跡をスタックに残します)。
各スタックは分離されているため、一見ランダムなメソッド呼び出しの連続チェーンが最終的にスタックをオーバーフローすることはありません (これは、相互に連続して呼び出しを行う標準 C メソッドを使用して単純にこのスキームを実装しようとした場合の結果である可能性があります)。これは、各ファイバーが作業中のステート マシンを保持し、定期的に呼び出し側のディスパッチャーのメソッドに戻るステート マシンを使用して手動で実装できますが、実際のファイバー/コルーチンのサポートが広く利用可能であるのに、なぜ面倒なのでしょうか?
また、協調マルチタスキングは、プロセス、保護されたメモリ、アドレス空間などと直交していることも覚えておいてください。Mac OS 9 または Windows 3.x を目撃してください。彼らは、個別のプロセスのアイデアを支持しました。しかし、譲ると、コンテキストが OS コンテキストに変更され、OS スケジューラが実行できるようになり、別のプロセスに切り替える可能性がありました。理論的には、協調マルチタスキングを使用しながら、完全に保護された仮想メモリ OS を使用できます。これらのシステムでは、誤ったプロセスが中断されない場合、OS スケジューラが実行されなかったため、システム内の他のすべてのプロセスがフリーズしていました。**
次の自然な質問は、何かをプリエンプティブにするものです...答えは、現在実行中のタスクを停止し、現在のタスクが解放されるかどうかに関係なく、OS が CPU で割り込みタイマーをスケジュールして、OS スケジューラのコンテキストに戻ることです。 CPU を使用するかどうかに関係なく、CPU を「プリエンプト」します。OS が CPU 特権レベルを使用している場合、(カーネルが構成された) タイマーは下位レベルの (ユーザー モード) コードではキャンセルできませんが、理論的には、OS がそのような保護を使用していない場合、誤ったタスクが割り込みタイマーをマスクしたりキャンセルしたりする可能性があります。 CPUを乗っ取ります。タイマーの外部でスケジューラを呼び出すことができる IO 呼び出しのような他のシナリオがいくつかあります。スケジューラは、他のプロセスの優先度が高くないと判断し、スイッチなしで同じプロセスに制御を戻す場合があります...そして実際には、ほとんどの OS はそうしません。
** 特定の時間内に yield が呼び出されない場合、タイマーを起動しない理由を尋ねるかもしれません。その答えは、マルチスレッド同期にあります。協調システムでは、物事が既知の良好な状態にある場合にのみ譲歩するため、わざわざロックを取得したり、再入を心配したりする必要はありません。この神話上のタイマーが起動した場合、中断されたプログラムの状態が破損している可能性があります。これを処理するためにプログラムを作成する必要がある場合は、おめでとうございます...これで、中途半端なプリエンプティブ マルチタスク システムが完成しました。ちょうどそれを正しく行うかもしれません!とにかく物事を変更する場合は、スレッドや保護されたメモリなどを追加することもできます。これは、主要な OS の歴史です。