VBScriptを掌握する極限の知見:レジストリによるプロセス間同期(IPC)の真髄
VBScriptという言語は、現代のコンテナやマイクロサービスから見れば「化石」に映るかもしれない。しかし、Windowsの心臓部(Win32 API)を直接叩けるこの言語は、適切に扱えば、軽量かつ環境依存を極限まで排除した最強のオートメーションツールに変貌する。
今回は、WSH(Windows Script Host)環境における最大の課題、「独立したプロセス間でのシグナル伝達と同期」をレジストリを用いて実装する手法を伝授する。
なぜレジストリを同期プリミティブに選ぶのか
本来、プロセス間通信(IPC)には名前付きパイプや共有メモリを用いるのが定石だ。しかし、VBScriptには低レベルなメモリ操作のインターフェースがない。そこで登場するのが、Windowsレジストリである。
レジストリは、OSによって排他制御が保証された「グローバルな状態管理ストレージ」だ。`WScript.Shell`オブジェクトの`RegRead`と`RegWrite`を使い、特定のキーを「ミューテックス(排他制御用信号)」として利用することで、別々のプロセスをセマフォのように制御できる。
実装の核心:レジストリ・セマフォの実装
以下のコードは、別々のタイミングで起動した複数のプロセスが、レジストリ上の「ロック」を確認し、処理の完了を待機する仕組みである。
‘ —————————————————————————
‘ RegistryMutex.vbs
‘ レジストリを介したプロセス同期制御クラス
‘ —————————————————————————
Class RegistryMutex
Private m_Shell
Private m_KeyPath
Private Sub Class_Initialize()
Set m_Shell = CreateObject(“WScript.Shell”)
‘ 同期用のキーパス(HKCU配下に置くことで権限問題を回避)
m_KeyPath = “HKCU\Software\MyProject\SyncSignal”
End Sub
‘ 処理開始のロック取得(スピンロック方式)
Public Sub AcquireLock()
Do
On Error Resume Next
‘ 現在のステータスを確認
Dim status
status = m_Shell.RegRead(m_KeyPath)
If Err.Number <> 0 Then ‘ キーが存在しない=ロック可能
m_Shell.RegWrite m_KeyPath, 1, “REG_DWORD”
On Error GoTo 0
Exit Sub
End If
On Error GoTo 0
WScript.Sleep 100 ‘ CPU負荷を抑えるためのインターバル
Loop
End Sub
‘ ロック解除
Public Sub ReleaseLock()
On Error Resume Next
m_Shell.RegDelete m_KeyPath
On Error GoTo 0
End Sub
Private Sub Class_Terminate()
Set m_Shell = Nothing ‘ メモリリーク防止のための明示的解放
End Sub
End Class
‘ — 使用例 —
Dim mutex : Set mutex = New RegistryMutex
mutex.AcquireLock
‘ — ここにクリティカルセクションの処理 —
WScript.Echo “処理中…”
WScript.Sleep 2000
‘ —————————————
mutex.ReleaseLock
Set mutex = Nothing
シニアエンジニアが意識すべき「極限の最適化」ポイント
このコードを現場で運用する際、以下の3点に注意せよ。これこそが「動くコード」と「止まらないコード」の分水嶺だ。
1. 永続化によるスタックオーバーフローの防止
プロセスが異常終了した場合、レジストリ上のロックキーが残留し、後続プロセスが永遠に起動しないデッドロックが発生する。これを防ぐには、WScriptの終了イベントを補足できないことを前提とした「TTL(Time To Live)」の概念を導入すべきだ。
レジストリ値にタイムスタンプを書き込み、現在時刻との差分が一定値を超えていたら、前回のプロセスが死んでいると見なして強制削除するロジックを`AcquireLock`に組み込むこと。
2. メモリ管理の規律
VBScriptのガベージコレクション(GC)は遅延が発生しやすい。特にループ内でオブジェクトを生成し続けると、メモリ断片化の原因となる。`Class_Terminate`での明示的な`Nothing`代入は、大規模なバッチ処理において必須の作法である。
3. レジストリアクセスのオーバーヘッド
レジストリへのアクセスはファイルI/Oを伴う重い処理だ。高頻度な同期を求められる場合、このアプローチは適さない。あくまで「日次処理の並列順序制御」や「排他制御が必要なファイル操作のゲートキーパー」として使用すること。
結論:レガシーを制御下に置く
VBScriptでシステムを組むということは、現代のブラックボックス化されたライブラリに頼らず、OSのAPIという生身のインターフェースと対話するということだ。
レジストリを用いたプロセス同期は、一見泥臭い手法に見えるが、OSの仕様そのものに依存しているため、極めて堅牢である。環境の変化に翻弄される高レベル言語のラッパーに逃げず、OSの基盤を理解し、その上で目的を達成する。それこそが、真にプロフェッショナルなエンジニアの矜持である。
今後はこの同期制御の上に、`FileSystemObject`を用いたログ出力の排他制御や、タスクスケジューラの動的制御を積み重ねていくと良い。道は、常にシンプルで強固な基礎の上にある。
