INtime でプロセスやスレッドを書いてきたエンジニアが RTX64 に移行すると、最初に戸惑うのがプロセス・スレッドの「作り方」の違いです。INtime はオブジェクト指向カーネルとして GDT スロットと RTHANDLE でリソースを統一管理しますが、RTX64(RTSS)は Windows のプロセスモデルを継承した独自サブシステムです。概念と API の対応を理解することが移行の第一歩となります。
INtime のプロセスモデル — オブジェクト指向カーネルとプロセスツリー
INtime カーネルはすべてのリソースを「カーネルオブジェクト」として統一管理します。プロセス、スレッド、セマフォ、リージョン、メールボックス — あらゆるものが RTHANDLE で識別されるカーネルオブジェクトです。
プロセスは ツリー構造(プロセスツリー)を形成します。システム起動時に Root Process が生成され、すべてのアプリケーションプロセスはその子孫として存在します。各プロセスはリソース(メモリプール)を親プロセスから取得します。
Root Process(カーネル起動時に生成)
├─ System Process A(カーネルシステムプロセス)
├─ System Process B
└─ Your Application Process(CreateRtProcess で起動)
├─ Thread 1(メインスレッド)
└─ Thread 2(ユーザー作成スレッド)
GDT スロット — INtime のリソース管理の核心
INtime がオブジェクト指向と呼ばれる理由のひとつが、GDT(Global Descriptor Table)によるリソース管理です。プロセッサの GDT は、メモリセグメントの記述子を管理するテーブルです。INtime はこの GDT のスロットを利用して、すべてのカーネルオブジェクトを管理しています。
重要な制限事項として、システム全体で高レベルオブジェクトは約 7,600 個までという上限があります(GDT の 8,192 スロットのうち、OS 自体が使用するスロットを除いた数)。この上限を超えると E_SLOT (0x000C) エラーが返されます。
// INtime: CreateRtThread の戻り値チェック
RTHANDLE hThread = CreateRtThread(
NULL_RTHANDLE, // 親プロセス(NULL = 呼び出し側プロセス)
0, // スタックサイズ(0 = デフォルト)
100, // 優先度(0が最高、254が最低)
myThreadFunc, // スレッド関数
NULL // 引数
);
if (hThread == NULL_RTHANDLE)
{
DWORD err = GetLastRtError();
if (err == E_SLOT)
{
// GDT スロットが満杯 — オブジェクト数が上限に達している
printf("ERROR E_SLOT: GDT slots full. Too many RT objects.
");
}
}
GDT スロット制限は INtime 独自の制約です。RTX64 に移行すると、この制限はなくなります(Windows カーネルのリソース制限が適用されます)。
INtime のメモリプール — 事前割り当て型メモリ管理
INtime の各プロセスは メモリプール(Memory Pool)と呼ばれる独自のメモリ空間を持ちます。プロセス内のすべてのスレッドはこのプールを共有しますが、異なるプロセス間ではメモリプールを共有できません。
メモリプールのサイズはリンカーの /HEAP パラメータまたは RT Application Loader のオプションで指定します。INtime はメモリを事前確保するため、リアルタイム動作中に動的なメモリ割り当てが発生しません。
// INtime: プロセスのメモリプール情報を取得
POOLINFO poolInfo;
DWORD ret = GetRtProcessPoolInfo(NULL_RTHANDLE, &poolInfo);
// poolInfo.dwUsed : 使用中バイト数
// poolInfo.dwTotal : プール総サイズ
RTX64(RTSS)のプロセスモデル — Windows HAL 拡張
RTX64 は Windows の HAL(Hardware Abstraction Layer)を拡張する形で動作します。RTSS は Windows とは独立したサブシステムとして存在しますが、プロセスモデルは Windows の考え方を継承しています。
RTSSプロセスは フラット構造で、INtime のようなツリー階層はありません。プロセスの実行ファイルには .rtss という拡張子が付きます。
Windows OS
├─ Windowsプロセス A(.exe)
├─ Windowsプロセス B(.exe)
└─ RTSS サブシステム(Windows とは独立して動作)
├─ RTSSプロセス 1(.rtss)— リアルタイム制御アプリ
└─ RTSSプロセス 2(.rtss)— モーション制御アプリ(WMX3等)
別の RTSSプロセスを起動するには、Windows 側のアプリから RtCreateProcess() を呼び出します(RTSS プロセス内から直接別の RTSS プロセスを作成することはできません)。
// RTX64: Windows アプリから RTSS プロセスを起動する
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = {};
BOOL ok = RtCreateProcess(
L"C:\RtApps\motion.rtss", // 絶対パス必須(相対パス不可)
nullptr, // コマンドライン引数
nullptr, nullptr, // セキュリティ属性
FALSE, // ハンドル継承なし
0, // 作成フラグ
nullptr, // 環境変数
L"C:\RtApps", // 検索ディレクトリ(省略可)
&si, &pi
);
if (!ok)
{
DWORD err = GetLastError();
// エラー処理
}
// pi.hProcess, pi.hThread が作成された
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
RTDLL — RTX64 の動的ライブラリ(INtime の共有ライブラリに相当)
INtime では共有ライブラリ(RTA 形式)を使いますが、RTX64 では RTDLL(Real-Time Dynamic Link Library)という独自の DLL を使用します。拡張子は .rtdll です。
| 項目 | INtime(共有ライブラリ) | RTX64(RTDLL) |
|---|---|---|
| ファイル形式 | .rta(RTアプリ/ライブラリ) | .rtdll |
| ロード方式 | ノードローカル管理 | 暗黙的ロード(リンク) / 明示的ロード(LoadLibrary) |
| プロセス間共有 | ノード単位で共有可能 | 共有不可(各プロセスが独自イメージを持つ) |
| 初期化関数 | 独自初期化 | DllMain(DLL_PROCESS_ATTACH/DETACH) |
| スレッド通知 | - | DLL_THREAD_ATTACH/DETACH は非サポート |
| Windows DLL との互換 | なし | Windows アプリからは通常の .dll を使用 |
RTDLL の重要な制限として、プロセス間では共有されない点に注意が必要です。2 つの RTSS プロセスが同じ RTDLL ファイルをロードした場合、それぞれが独自のメモリイメージを持ちます。したがって、RTDLL 内のグローバル変数はロードしたプロセスにプライベートです。
スレッドの比較 — 優先度・アフィニティの違い
スレッドの作成方法と優先度体系が INtime と RTX64 では大きく異なります。
| 項目 | INtime | RTX64(RTSS) |
|---|---|---|
| スレッド作成 API | CreateRtThread() | CreateThread()(Windows と同じ) |
| スレッドハンドル型 | RTHANDLE | HANDLE(Windows 互換) |
| 優先度範囲 | 0〜254(0 が最高) | 0〜127(0 が最高) |
| プロセス優先度クラス | あり(プロセスの最大優先度制限) | なし(スレッド優先度のみで制御) |
| アフィニティ | ノード内のコアに割り当て可能 | Static モデル(動的移動なし、Ideal Processor 保証) |
| 優先度設定 API | SetRtThreadPriority() | RtSetThreadPriority() |
// INtime: スレッド作成と優先度設定
RTHANDLE hThread = CreateRtThread(
NULL_RTHANDLE, // 親プロセス
0, // スタックサイズ(0=デフォルト)
50, // 優先度(0〜254、INtime では数値が小さい = 高優先度)
myRtThreadFunc,
NULL
);
// RTX64(RTSS): Windows CreateThread に近い形
HANDLE hThread = CreateThread(
nullptr, // セキュリティ属性
0, // スタックサイズ(0=デフォルト)
myRtssThreadFunc,
nullptr,
0,
nullptr
);
// 優先度は別途設定
RtSetThreadPriority(hThread, 50); // 0〜127(0が最高)
ハンドル型の対応 — RTHANDLE vs HANDLE
INtime では RTHANDLE がすべてのカーネルオブジェクトを統一的に表しますが、RTX64 では Windows の HANDLE 型がその役割を担います。
// INtime の主要な RTHANDLE 利用例
RTHANDLE hProcess; // プロセスハンドル
RTHANDLE hThread; // スレッドハンドル
RTHANDLE hSem; // セマフォハンドル
RTHANDLE hRegion; // リージョン(ミューテックス相当)ハンドル
RTHANDLE hMailbox; // メールボックスハンドル
// RTX64(RTSS)の HANDLE 利用例(Windows 互換型)
HANDLE hThread; // スレッドハンドル
HANDLE hEvent; // イベントハンドル(RtCreateEvent)
HANDLE hMutex; // ミューテックスハンドル(RtCreateMutex)
HANDLE hSem; // セマフォハンドル(RtCreateSemaphore)
全体比較まとめ
| 比較項目 | INtime | RTX64(RTSS) |
|---|---|---|
| カーネルの思想 | オブジェクト指向 RTOS(独自カーネル) | Windows HAL 拡張(RTSS サブシステム) |
| プロセス構造 | ツリー(Root → 親 → 子) | フラット(Windows と並列) |
| リソース管理基盤 | GDT スロット(約 7,600 個上限) | Windows カーネルリソース |
| ハンドル型 | RTHANDLE | HANDLE(Windows 互換) |
| 動的ライブラリ | .rta(共有ライブラリ) | .rtdll(プロセス非共有) |
| スレッド優先度 | 0〜254(0 が最高) | 0〜127(0 が最高、クラスなし) |
| メモリ管理 | メモリプール(事前割り当て、/HEAP 指定) | ロック済み仮想メモリ(malloc 可) |
| プロセス起動 API | CreateRtProcess() / ntxCreateRtProcess() | RtCreateProcess()(Windows 側から) |
移行時の注意点
- GDT スロット制限はなくなる:INtime では最大 7,600 オブジェクトという制限がありましたが、RTX64 ではこの制限がなくなります。ただし Windows カーネルのリソース制限(HANDLE数など)は別途あります。
- RTHANDLE → HANDLE への読み替え:ハンドル型が変わるため、既存コードの型宣言をすべて見直す必要があります。
- スレッド優先度の範囲縮小:INtime の 0〜254 から RTX64 の 0〜127 に半減します。優先度設計を見直してください。
- RTDLL はプロセス間共有不可:グローバル変数を複数プロセスで共有していた場合は、共有メモリ(RtCreateSharedMemory)への移行が必要です。
- DLL_THREAD_ATTACH/DETACH が来ない:RTDLL の DllMain ではスレッドの通知を受け取れません。スレッドローカルな初期化は別の方法で行ってください。
- プロセス起動は Windows 側から:RTX64 では RTSS プロセス内から直接別の RTSS プロセスを起動する仕組みがありません。起動制御は Windows アプリが担います。
終わりに
日本では、INtimeユーザが多いとよく聞きます。けど、WMXを使うにはRTXを使う必要があります。開発環境が2つになってしまった方へ少しでも戸惑いが減りますように。 良きWMXライフを!


コメント