メインフレームの闇に光を:PL/Iマルチスレッド環境におけるSTATIC変数の「生存戦略」
長年メインフレームの現場でPL/Iのコードと格闘してきたが、近年のマイグレーション案件や、バッチ処理の高速化を目的としたスレッド化(Language Environment/LEの並列処理)において、未だに多くのエンジニアが躓くポイントがある。それが「STATIC変数のスレッド安全性(Thread-Safety)」だ。
単一のメインプログラムから呼び出される手続き(PROCEDURE)で動いていたコードを、いざCICSのタスクサブタスクや、LEの`CEECRTS`で並列化しようとした途端、データが化ける。あるいは「なぜか特定の条件でだけabendする」。そんな悪夢を見たことはないだろうか?
今日は、STATIC変数がマルチスレッド環境でどう振る舞うのか、そしてどう制御すべきか、現場の視点で深掘りしていく。
—
1. STATIC変数の「素顔」とマルチスレッドの不都合な真実
PL/Iの`STATIC`属性は、プログラム実行中ずっとメモリ上に居座り続ける「長老」のような存在だ。コンパイルされたプログラムのロードモジュールの一部として確保され、初期化は一度きり。これは手続き間の共通データとして非常に便利だが、マルチスレッド環境では「共有リソース」として競合の源泉になる。
もし、あるスレッドAが`STATIC`変数を更新している最中に、スレッドBが横から値を参照したらどうなるか? データの不整合、あるいは予測不可能な論理エラーが発生するのは自明の理だ。
解決策:THREAD属性の活用
IBMのPL/Iコンパイラは、`STATIC`変数に`THREAD`属性を付与することで、その変数をスレッドごとに個別に割り当てることができる。
/i
/ スレッド単位で個別の実体を持つSTATIC変数 /
DCL MY_THREAD_DATA CHAR(80) STATIC THREAD;
これを指定すると、コンパイラとLE環境が連携し、スレッド生成時にそのスレッド固有のデータ領域を確保してくれる。これで競合は物理的に回避できるわけだ。
—
2. 実践コード:スレッドセーフなカウンターの実装
例えば、VSAMファイルを読み込みながら処理件数をカウントし、ログに出力するような処理を考えてみよう。複数のスレッドで同時に回す場合、単純なSTATICカウンターではカウントが合わなくなる。
/i
MY_PROG: PROCEDURE OPTIONS(MAIN);
/ 競合を防ぐためTHREAD属性を付与 /
DCL PROC_COUNT FIXED BIN(31) STATIC THREAD INIT(0);
/ VSAMファイルの制御用 /
DCL VSAM_REC CHAR(100);
/ 入出力エラー時のONユニット(基本中の基本) /
ON ENDFILE(VSAM_FILE) BEGIN;
PUT SKIP LIST(‘処理終了。累計件数: ‘ || PROC_COUNT);
END;
/ メインループ:各スレッドから独立して呼び出される想定 /
DO WHILE(1);
READ FILE(VSAM_FILE) INTO(VSAM_REC);
/ 処理件数をインクリメント /
/ THREAD属性のおかげで、他スレッドの干渉を受けない /
PROC_COUNT = PROC_COUNT + 1;
/ 複雑な処理ロジックがここに入る /
CALL PROCESS_DATA(VSAM_REC);
END;
END MY_PROG;
—
3. 現場で生き残るための「鉄則」とデバッグの極意
コードを書く上で、以下の3点は絶対に忘れないでほしい。
1. THREAD属性を乱用しないこと
`THREAD`属性を付ければ確かに安全だが、メモリ消費量はスレッド数に比例して増える。スレッド数が動的に増減する環境では、スタックオーバーフローやメモリ不足(Abend S80Aなど)のリスクを考慮する必要がある。
2. VSAMアクセスと排他制御
`STATIC`変数がスレッドローカルになっても、VSAMファイル自体は共有リソースだ。ファイルオープン時の`SHAREOPTIONS`設定を誤れば、PL/I側でどんなに綺麗に制御しても、データセットレベルでエンキュー待ちが発生する。`ENQ/DEQ`マクロの理解は必須だ。
3. ONユニットの局所化
マルチスレッド下で`ON`ユニットが全体に影響を及ぼすと、予期せぬスレッドでエラーが発生した際、メイン処理が巻き込まれて共倒れする。`BEGIN`ブロックでスコープを適切に閉じ、スレッド内で完結するエラーハンドリングを徹底すること。
—
最後に:レガシーを「活かす」ということ
PL/Iという言語は、非常に厳格で、かつ強力だ。現代のプログラミング言語のように「よしなに」やってはくれない。しかし、だからこそハードウェアの性能を極限まで引き出せるし、メインフレーム特有の膨大なトランザクションを捌ききることができる。
`STATIC`変数の管理一つとっても、それは単なるコーディング規約ではなく、システムの安定性を左右する「アーキテクチャの意思」だ。後輩諸君には、ただ動くコードを書くだけではなく、その変数がメモリ上のどこに配置され、スレッドがどうアクセスするのか、脳内でシミュレーションできるエンジニアになってほしい。
バッチ改修で夜中に呼び出されたとき、最後に自分を助けてくれるのは、こうした「泥臭い仕様の理解」なのだから。
