1. 導入:なぜEXTERNAL属性が重要なのか
メインフレームのCOBOLやPL/I開発において、複数のプログラム(コンパイル単位)間で同じデータを参照・更新したい場面は多々あります。その際に「いちいち引数として渡すのは面倒だ」と感じたことはありませんか?
EXTERNAL属性を使えば、プログラム間で変数を直接共有することが可能です。これにより、共通の制御フラグやカウンターを複数のモジュールから参照できるようになり、プログラム構成をシンプルに保つことができます。
2. 基礎知識:EXTERNAL属性の仕組み
通常、プログラム内で宣言した変数はそのプログラム内でのみ有効ですが、EXTERNAL属性を付与すると、その変数は「外部シンボル」として扱われます。
具体的には、以下の流れでデータが共有されます。
・コンパイル時:コンパイラは変数を「外部参照可能」としてマークします。
・リンク時(リンケージエディタ):複数のプログラムで宣言された同じ名前のEXTERNAL変数を、メモリ上の同一アドレスに関連付けます。
これにより、Aプログラムで値を書き換えると、Bプログラムからもその変更後の値が即座に読み取れるようになります。
3. 実装・解決策
実装は非常にシンプルで、変数宣言の末尾に「EXTERNAL」と記述するだけです。ただし、データ型やサイズが一致していないと、メモリの破損や誤った値の読み取りが発生するため、共通のコピーブック(COPY文)で定義を管理するのが鉄則です。
4. サンプルプログラム
以下は、PL/Iを想定した簡単なサンプルコードです。共通のカウンターを複数のプログラムで共有する例です。
/ — 共通定義ファイル (COPYBOOK: COUNTER.INC) — /
/ 複数のプログラムで同じ定義を参照させるためにコピーブック化します /
DCL GLOBAL_COUNT FIXED BIN(31) EXTERNAL;
/ — メイン処理プログラム (PROG01.PLI) — /
PROG01: PROC OPTIONS(MAIN);
%INCLUDE COUNTER; / 共通定義を読み込む /
GLOBAL_COUNT = 100; / 値をセット /
PUT SKIP LIST(‘PROG01で設定しました:’, GLOBAL_COUNT);
CALL PROG02; / 別のプログラムを呼び出す /
PUT SKIP LIST(‘PROG02終了後の値:’, GLOBAL_COUNT);
END PROG01;
/ — サブ処理プログラム (PROG02.PLI) — /
PROG02: PROC;
%INCLUDE COUNTER; / 同じ定義を読み込むことで変数を共有 /
/ PROG01で設定した値を参照・加算する /
GLOBAL_COUNT = GLOBAL_COUNT + 50;
PUT SKIP LIST(‘PROG02で加算しました:’, GLOBAL_COUNT);
END PROG02;
5. 応用・注意点:移行とスレッドセーフ
最後に、モダンな環境への移行を考える際に最も重要な注意点をお伝えします。
メインフレームでは「単一プロセス・シングルスレッド」が前提であることが多いですが、Javaなどのモダンな環境へ移行する場合、EXTERNAL変数はスレッドセーフではないという点に注意が必要です。
複数のスレッドから同時にGLOBAL_COUNTにアクセスすると、データの不整合が発生します。Javaへ移行する際は、単なる静的フィールドとして定義するのではなく、AtomicIntegerを使用したり、SingletonパターンやSpringのBean管理を利用して、排他制御を考慮した設計に作り替えることが必須となります。現場でトラブルを避けるためにも、今のうちから「この変数はどこからアクセスされるのか」を意識する癖をつけておきましょう。

コメント