TadaoYamaokaの日記

山岡忠夫Homeで公開しているプログラムの開発ネタを中心に書いていきます。

WindowsでプロセスにSIGINTを送る

将棋AIの自己対局のプログラムで途中で中断(Ctrl+C)した場合に、それまでに生成した局面を安全にファイルに書き出すためにSIGINTをハンドリングしている。
ただし、今までは、基本的に途中で中断しないで、生成する局面の数を引数として、自己対局完了→学習の順にシーケンシャルに処理していた。

現在1台のPCにGPUを3枚刺して使用しており、学習は1枚のGPUで行っているため、学習中に他の2枚が無駄になっている。
そこで、GPUを有効活用するため、学習中にも自己対局を行い、学習完了時にSIGINTを送信して自己対局を安全に中断するようにした。

なお、自己対局のプログラムが新しいモデルがあれば取りに行くような仕組みの方がエレガントだが、一連の処理をWindowsのバッチファイルで処理するダサい仕組みになっている。

以下、処理方式に関する説明です。

SIGINTの受信処理

C++では、

#include <signal.h>

volatile sig_atomic_t stopflg = false;

void sigint_handler(int signum)
{
	stopflg = true;
}

int main() {
    signal(SIGINT, sigint_handler);
    // ...
}

のようにして、SIGINTをハンドリングできる。

学習と自己対局を並列で実行

バッチファイルでプログラムを並列で実行するために、startコマンドで自己対局を別のコマンドプロンプトで起動してから学習を行うようにした。
ログをリダイレクトで出力していたため、直接自己対局プログラムを起動するのではなく、cmdコマンドを起動してその引数に実行するコマンド行を記述するようにした。

start cmd /c "make_hcpe_by_self_play --mate_depth 25 --mate_nodes 100000 --threashold 1 d:\model\model_rl_val_wideresnet10_selfplay_%M% C:\hcp\roots12.hcp D:\selfplay\selfplay-%N%_org3 100000 1000 1 256 2 256 >> d:\log\%date:~0,4%%date:~5,2%%date:~8,2%_make_hcpe_by_self_play_%N%.txt"

SIGINTの送信

学習完了後に、並列で実行中の自己対局プログラムを終了するために、SIGINTを送信する。
Windowsで標準でSIGINTを送信する方法がないため、windows-killというコマンドを使用した。
なお、標準のプロセスを終了するコマンドとしてtaskkillコマンドがあるが、SIGINTは送信できない。

windows-killコマンドは引数がPIDになっているため、tasklistコマンドでPIDを取得する必要がある。

for /f "tokens=2 delims=, usebackq" %%i in (`tasklist /nh /fo csv /fi "imagename eq make_hcpe_by_self_play.exe"`) do set pid=%%i

これで、変数pidに自己対局プログラムのPIDが設定されるので、

C:\bin\windows-kill\windows-kill.exe -SIGINT %pid%

のようにしてSIGINGを送信する。

その後、自己対局プログラムが終了するのを待つ必要があるため、powershellのWait-Processを使って待つようにした。

powershell -Command Wait-Process -Id %pid%


以上、バッチファイルでプロセスの並列処理を頑張る方法についてでした。
たぶん、バッチファイルで頑張るよりPythonとかで作った方がよいです。