【テクニカル・上級編】【マルチプロセス同期】Windowsレジストリを利用した別VBScriptプロセス間でのシグナル伝達と同期制御 – VBScript (Visual Basic Scripting Edition)解析バイブル

スポンサーリンク

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`を用いたログ出力の排他制御や、タスクスケジューラの動的制御を積み重ねていくと良い。道は、常にシンプルで強固な基礎の上にある。

タイトルとURLをコピーしました