10. ファイバー
ファイバー (Fiber) は軽量スレッド (Lightweight Thread) や、マイクロスレッド (Micro Thread) とも呼ばれます。端的に言えば、並行動作しない疑似的なスレッドです。
ファイバーは実質的に コルーチン と同じで、Pascal の後継言語である Modula-2 にはコルーチンが実装されています。Pascal の方言にもコルーチンが実装されたものがあったようです。
サブルーチン (≒ Pascal の Procedure) は常に先頭からしか実行できませんが、コルーチンは中断したり中断した所から再開する事ができます。
スレッドがプリエンティブマルチタスク (Preemptive multitasking) みたいなものだとすると、ファイバーはノンプリエンプティブマルチタスク (Non-preemptive multitasking) / 協調的マルチタスク (Cooperative multitasking) みたいなものです。
- ファイバー (コンピュータ) (Wikipedia)
- コルーチン (Wikipedia)
- 割と簡単に ’標準 Modula-2 / Oberon-2' を試してみたい (Qiita)
- COMTAY coroutine manager (OpenSIMPLY)
- Example - COMTAY coroutine manager (OpenSIMPLY)
10.1. Delphi とファイバー
Delphi には言語標準のファイバー (やコルーチン) は実装されていません。
Windows にはファイバー API が存在するので、Windows アプリケーションの場合にはこれを使う事になります。ファイバー API は Winapi.Windows
名前空間で定義されています。
Windows API | 説明 |
---|---|
CreateFiber() | ファイバー オブジェクトを割り当て、スタックを割り当て、指定した開始アドレス (通常はファイバー関数) で開始するように実行を設定します。 |
CreateFiberEx() | ファイバー オブジェクトを割り当て、スタックを割り当て、指定した開始アドレス (通常はファイバー関数) で開始するように実行を設定します。 |
SwitchToFiber() | ファイバーをスケジュールします。 |
ConvertFiberToThread() | 現在のファイバーをスレッドに変換します。 |
ConvertThreadToFiber() | 現在のスレッドをファイバーに変換します。 ※12 Athens よりも前の Delphi では定義が間違っています。 |
ConvertThreadToFiberEx() | 現在のスレッドをファイバーに変換します。 |
DeleteFiber() | 既存のファイバーを削除します。 |
GetFiberData() | 現在のファイバーに関連付けられているファイバー データを取得します。 |
IsThreadAFiber() | 現在のスレッドがファイバーであるかどうかを判断します。 |
ファイバー API はかなり古くからある API で、Windows NT 3.51 SP3 で実装されています。
画像は Nifty-Serve の FDELPHI に投稿されたファイバー API の使用例を実行してみたところです。2つの PaintBox を同時にグラデーション描画します。
See also:
- ファイバー (learn.microsoft.com)
- ファイバーの使用 (learn.microsoft.com)
- Implementing Coroutines for .NET by Wrapping the Unmanaged Fiber API (learn.microsoft.com)
- "Fiber(ファイバ)" - FDELPHI (DelFusa Floor)
- Coroutine - ObjectPascal Magic Programming (いつも心に工事中!)
- The ConvertThreadToFiber() API is incorrectly defined (Quality Portal)
10.1.1. シンプルなサンプル
簡潔なサンプルです。フォームにはメモが 2 つとボタンが 1 つあり、ボタンが押されるとそれぞれのメモに Hello,
world.
が書き込まれます。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Memo2: TMemo;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
type
PMemo = ^TMemo;
var
Form1: TForm1;
MainFiber: Pointer;
SubFiber: array [0..1] of Pointer;
Memo: array [0..1] of TMemo;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo[0] := Memo1;
Memo[1] := Memo2;
MainFiber := ConvertThreadToFiber(nil);
end;
procedure FiberProc(lpFiberParameter: Pointer); stdcall;
begin
var Memo := PMemo(lpFiberParameter)^;
while True do
begin
Memo.Lines.Add('Hello,');
SwitchToFiber(MainFiber);
Memo.Lines.Add('world.');
SwitchToFiber(MainFiber);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
for var i:=0 to 1 do
SubFiber[i] := CreateFiber(0, @FiberProc, @Memo[i]);
try
SwitchToFiber(SubFiber[0]);
SwitchToFiber(SubFiber[1]);
SwitchToFiber(SubFiber[0]);
SwitchToFiber(SubFiber[1]);
SwitchToFiber(SubFiber[0]);
SwitchToFiber(SubFiber[0]);
SwitchToFiber(SubFiber[1]);
SwitchToFiber(SubFiber[1]);
finally
for var i:=0 to 1 do
DeleteFiber(SubFiber[i]);
end;
end;
end.
少なくとも 1 つのファイバーは ConvertThreadToFiber()
を使用してスレッドから変換する必要があるため、MainFiber はメインスレッドから変換されています。
10.2. Windows のユーザーモードスケジューラ (UMS)
Windows 7 で実装された ユーザーモードスケジューラ (UMS) は端的に言えば「ファイバーのような機構を提供するもの」です。
- 64bit カーネル 専用。
- Windows 10 が Anniversary Update 以降の場合、Ivy Bridge よりも前の CPU では動作しない。
- (2022/12 現在) Windows 11 では動作しない。
うーん。
See also:
- ユーザーモードスケジューリング (learn.microsoft.com)
- Inside Windows 7: Dave Probert - User Mode Scheduler (UMS) (Youtube)
- Bringing Call Gates Back (ALEX IONESCU’S BLOG)
索引
[ ← 9. 非同期プログラミングライブラリ (APL) ] [ ↑ 目次へ ] [ → 付録 ]