コマンドキュー
2021年2月5日 (金) 03:00時点におけるAdministrator (トーク | 投稿記録)による版
コマンドキュー(英語:command queue)とは、特定のコマンド(処理)をキューに格納しておくと、別のプロセスやスレッドが適宜それを取り出して実行する方式のことである。
一部の実装では単純なキューではなく、キューの中においてコマンドの実行順序を並べ替えたりコマンドを結合したりといった最適化が行われることがある。
マルチスレッドにおける「スレッドプール」もほぼ同じ概念である。スレッドプールでは汎用的な処理を格納することができるが、コマンドキューの場合は前述のような最適化が行いやすいように単純なコマンドであることが多い。
目次
主な実装例
ハードディスクのNCQ
最近のハードディスクにはNCQ (Native Command Queue)という機構が搭載されており、1つの読み書き依頼が1つのコマンドとしてコマンドキューに格納される。複数の処理待ちが発生している場合はコマンドキューの中で磁気ヘッドの動きが最小になるように最適化してから実際の読み書き処理が行われる。
GPUのコマンドリスト
最近のGPUでは1フレームの描画処理をコマンドキューに格納して実行する方式が主流となっている。こちらは「CPUがGPUの処理完了を待たないための機構」という意味合いが強く、GPUが別スレッドのような扱いになる。
架空のコマンドセットを示す。
void Draw() {
// コマンドリストを作る
var cl = new CommandList();
cl.Add(new SetFrameBufferCommand()); // フレームバッファをセットする
cl.Add(new ClearCommand() ); // フレームバッファをクリアする
// コマンドキューに格納する
GraphicsDevice.SubmitCommands(cl);
// ここで処理完了を待てば従来同様になる。
// ただWaitForIdle()している間はCPUが遊んでしまう。
//GraphicsDevice.WaitForIdle();
}
GPUでの描画処理の場合は、前回の描画処理が未完了なのに次の描画処理を始めると残念なことになる。そこで「フェンス」と呼ばれるシグナル状態を保持する変数を用いて適切に処理する必要がある。 <source lang="csharp"> var fence;
void Init() {
fence = GraphicsDevice.CreateFence();
}
void Draw() {
// 前回の処理完了を待つ // ここで待たずにフレームスキップするのも手である。 //if (!fence.Signaled) // return; GraphicsDevice.WaitForFence(fence);
// コマンドリストを作る var cl = new CommandList(); cl.Add(new SetFrameBufferCommand()); // フレームバッファをセットする cl.Add(new ClearCommand() );
// コマンドキューに格納する GraphicsDevice.SubmitCommands(cl, fence); // ここで待たないのが重要
}