【PL/I学習|実務向け】PL/IにおけるNONCONNECTED配列の罠:隠れたコピー操作と性能劣化の回避策

導入

メインフレームのPL/I開発において、配列のサブセット(行列の行など)をサブルーチンへ渡す際、何気なく記述している「参照渡し」が、実は「隠れたコピー操作」を引き起こしていることをご存知でしょうか。この現象はNONCONNECTED(非連続)配列の参照時に発生し、予期せぬCPU消費や、マルチスレッド環境でのデータ整合性エラーを招く原因となります。本稿では、この挙動の仕組みと、性能劣化を防ぐための実装指針を解説します。

基礎知識

PL/Iにおいて、配列は基本的にメモリ上で連続した領域として配置されます。しかし、MATRIX(I, )のように行列の「行」を抽出する場合、メモリ上では離散的な領域となります。これを「NONCONNECTED(非連続)」状態と呼びます。コンパイラは、引数として受け取るサブルーチン側が「連続した配列」を期待していると判断した場合、呼び出しの直前に一時的なメモリ領域を確保し、値をコピーしてからサブルーチンを呼び出します。サブルーチン終了時には、その一時領域から元の配列へ値を書き戻す処理が発生します。これを「Dummy Argument(ダミー引数)」の生成と呼びます。

実装/解決策

この問題を回避する最も効果的な方法は、サブルーチン側の引数定義で、コンパイラに対して「この引数は非連続である可能性がある」と明示することです。具体的には、引数の宣言に「CONTROLLED」や「ALIGNED」といった属性だけでなく、コンパイラがコピーを強制しないようなインターフェース設計を行う必要があります。理想的には、コピーを発生させないために、可能な限り連続した配列構造を維持する設計が望ましいです。

サンプルプログラム

以下のコードは、NONCONNECTEDな引数渡しが発生するケースと、それを安全に処理するための定義例です。

/ 呼び出し元 /
DCL MATRIX(10, 10) FIXED BIN(31);
/ MATRIX(5, ) は行抽出のためNONCONNECTEDになる /
CALL PROCESS_ROW(MATRIX(5, ));

/ サブルーチン側 /
/ DEFINED属性やBYADDR属性を意識した宣言が必要 /
PROCESS_ROW: PROC(P_ROW) OPTIONS(BYADDR);
/ 引数には非連続であることを示す属性を指定する /
DCL P_ROW() FIXED BIN(31) NONCONNECTED;

DCL I FIXED BIN(31);
DO I = 1 TO HBOUND(P_ROW, 1);
/ ここで直接処理を行う /
P_ROW(I) = P_ROW(I) 2;
END;
END PROCESS_ROW;

応用・注意点

1. 性能への影響:
大量のデータを扱うループ内でこのコピーが発生すると、メモリ確保・解放のオーバーヘッドが無視できなくなります。パフォーマンスクリティカルな箇所では、そもそもNONCONNECTEDな参照を避けるよう、データの持ち方(行優先から列優先への変更など)を見直すことが重要です。

2. マルチスレッド・非同期処理へのリスク:
最も注意すべきは、非同期実行時に「書き戻し」が完了する前に別のタスクが元の配列を参照してしまうケースです。データの不整合が極めて特定しにくいバグとなるため、非同期処理を導入する際は、共有データ領域に対しては必ず「連続したメモリ構造」を保証した上で、排他制御を厳格に行ってください。

3. デバッグのヒント:
コンパイラの生成するリスト(LISファイル)を確認し、引数渡しにおいて「DUMMY」の文字や「COPY」に関連する警告が出ていないかを定期的にチェックする癖をつけましょう。これに気づくだけで、現場でのトラブルシュートの質が大きく向上します。

コメント

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