回答:
最も単純な用語では、スレッドは一般にプリエンプティブであると見なされます(ただし、オペレーティングシステムによっては、これが常に当てはまるとは限りません)。ファイバーは軽量の協調スレッドであると見なされます。どちらもアプリケーションの個別の実行パスです。
スレッドあり:現在の実行パスはいつでも中断またはプリエンプトされる可能性があります(注:このステートメントは一般化であり、OS /スレッド化パッケージなどによっては常に当てはまるとは限りません)。つまり、スレッドの場合、データのチャンクの更新中に1つのスレッドが停止し、データの整合性が不良または不完全な状態になるため、データの整合性が大きな問題になります。これは、オペレーティングシステムが複数のCPUとCPUコアを利用して、同時に複数のスレッドを実行し、開発者に任せてデータアクセスを保護できることも意味します。
ファイバーあり:現在の実行パスは、ファイバーが実行を生成したときにのみ中断されます(上記と同じメモ)。つまり、ファイバーは常に明確に定義された場所で開始および停止するため、データの整合性はそれほど問題になりません。また、ファイバーはユーザー空間で管理されることが多いため、高価なコンテキストスイッチやCPU状態の変更を行う必要がなく、ファイバーを次のファイバーに非常に効率的に変更できます。一方、2つのファイバーを同時に実行することはできないため、ファイバーのみを使用しても、複数のCPUや複数のCPUコアを利用することはできません。
スレッドはプリエンプティブスケジューリングを使用しますが、ファイバーは協調スケジューリングを使用します。
スレッドを使用すると、制御フローがいつでも中断され、別のスレッドが引き継ぐ可能性があります。複数のプロセッサを使用すると、複数のスレッドをすべて同時に実行できます(同時マルチスレッド、またはSMT)。その結果、同時データアクセスに非常に注意し、ミューテックス、セマフォ、条件変数などでデータを保護する必要があります。多くの場合、正しく理解するのは非常に困難です。
ファイバーを使用すると、通常はのような名前の関数呼び出しを使用して、制御が指示したときにのみスイッチが切り替わりますyield()
。これにより、データ構造やミューテックスの原子性について心配する必要がないため、同時データアクセスが容易になります。譲歩しない限り、プリエンプトされたり、作業中のデータを別のファイバーが読み取ったり変更したりする危険はありません。ただし、結果として、ファイバーが無限ループに陥ると、他のファイバーが実行できなくなります。
また、糸と繊維を混ぜることもできます。これは、両方が直面する問題を引き起こします。推奨されていませんが、慎重に行うと、正しいことになる場合があります。
Win32では、ファイバーはユーザー管理のスレッドの一種です。ファイバーには独自のスタックや独自の命令ポインターなどがありますが、ファイバーはOSによってスケジュールされていません。SwitchToFiberを明示的に呼び出す必要があります。対照的に、スレッドはオペレーティングシステムによって事前にスケジュールされます。つまり、ファイバーとは、真のOSスレッドではなく、アプリケーション/ランタイムレベルで管理されるスレッドです。
その結果、ファイバーは安価になり、アプリケーションはスケジューリングをより細かく制御できるようになります。これは、アプリが多数の同時タスクを作成する場合や、実行時に厳密に最適化する場合に重要になります。たとえば、データベースサーバーは、スレッドではなくファイバーの使用を選択する場合があります。
(同じ用語には他の用法があるかもしれません。注記したように、これはWin32の定義です。)
まず、プロセスとスレッドの違いに関するこの説明を背景資料として読むことをお勧めします。
それを読んだら、それはかなり簡単です。スレッドは、カーネル、ユーザー空間のいずれかに実装することも、2つを混在させることもできます。ファイバーは基本的にユーザー空間で実装されるスレッドです。
現代のオペレーティングシステムのセクション11.4「Windows Vistaのプロセスとスレッド」で、タネンバウムは次のようにコメントしています。
ファイバーは協調的にスケジュールされますが、ファイバーをスケジュールする複数のスレッドがある場合、ファイバーが互いに干渉しないようにするために、多くの注意深い同期が必要です。スレッドとファイバー間の相互作用を簡素化するには、多くの場合、スレッドを実行するプロセッサーの数と同じ数のスレッドのみを作成し、使用可能なプロセッサーの個別のセットまたは1つのプロセッサーでのみ実行するようにスレッドをアフィニティ化すると便利です。次に、各スレッドはファイバーの特定のサブセットを実行し、同期を簡素化するスレッドとファイバー間の1対多の関係を確立します。それでも、繊維にはまだ多くの問題があります。ほとんどのWin32ライブラリはファイバーを完全に認識していないため、スレッドのようにファイバーを使用しようとするアプリケーションでは、さまざまなエラーが発生します。カーネルはファイバーを認識していないため、ファイバーがカーネルに入ると、実行中のスレッドがブロックし、カーネルがプロセッサ上の任意のスレッドをスケジュールして、他のファイバーを実行できないようにします。これらの理由により、ファイバーが提供する機能を明示的に必要とする他のシステムからコードを移植する場合を除いて、ファイバーが使用されることはほとんどありません。
スレッドとファイバーに加えて、Windows 7ではユーザーモードスケジューリングが導入されています。
ユーザーモードスケジューリング(UMS)は、アプリケーションが独自のスレッドをスケジュールするために使用できる軽量のメカニズムです。アプリケーションは、システムスケジューラを使用せずにユーザーモードでUMSスレッドを切り替え、UMSスレッドがカーネルでブロックされた場合にプロセッサの制御を取り戻すことができます。UMSスレッドは、各UMSスレッドが単一のスレッドのスレッドコンテキストを共有するのではなく、独自のスレッドコンテキストを持つという点でファイバーとは異なります。ユーザーモードでスレッドを切り替える機能により、UMSはスレッドプールよりも効率的で、システムコールをほとんど必要としない多数の短期間の作業項目を管理できます。
スレッド、ファイバー、UMSの詳細については、Dave Probert:Inside Windows 7-User Mode Scheduler(UMS)をご覧ください。
一般に、スレッドはカーネルに依存してスレッドを中断するので、スレッドまたは別のスレッドを実行できます(これはプリエンプティブマルチタスクとして知られています)。一方、ファイバーは、ファイバー自体が実行時間を放棄する協調マルチタスクを使用します。他の繊維が走る可能性があります。
私がおそらくやったよりもそれをよりよく説明するいくつかの便利なリンクは:
Win32ファイバーの定義は、実際にはSun Microsystemsで確立された「グリーンスレッド」の定義です。ある種のスレッド、つまりユーザーコード/スレッドライブラリ制御下のユーザー空間で実行されているスレッドでファイバーという用語を無駄にする必要はありません。
引数を明確にするために、次のコメントを見てください。
プロセスは糸で作られ、糸は繊維で作られるべきだと仮定するべきです。そのロジックを念頭に置いて、他の種類のスレッドにファイバーを使用することは間違っています。