私たちを正しい方向に導いてくれた Jonathan Leffler に感謝します。
あなたのプログラムは、CentOS 7 / GCC 4.8.5 / GLIBC 2.17 で同じ予期しない動作を生成しませんが、異なる動作を観察する可能性があります。あなたのプログラムの動作は実際には未定義です POSIX による (fork
に依存する) )。関連するセクションからの抜粋を次に示します (強調を追加):
開いているファイルの説明は、open()
などの関数を使用して作成されるファイル記述子を介してアクセスできます。 または pipe()
、または fopen()
などの関数を使用して作成されるストリームを介して または popen()
.ファイル記述子またはストリームは、それが参照する openfile 記述の「ハンドル」と呼ばれます。開いているファイルの説明には、複数のハンドルがある場合があります。
[...]
任意の 1 つのハンドル (「アクティブ ハンドル」) を含む関数呼び出しの結果は、POSIX.1-2017 のこのボリュームの別の場所で定義されていますが、2 つ以上のハンドルが使用され、それらのいずれかがストリームである場合、アプリケーションはそれらのアクションは、以下で説明するように調整されます。 これが行われない場合、結果は未定義です .
[...]
ハンドルがアクティブ ハンドルになるには、アプリケーションは、ハンドルの最後の使用 (現在のアクティブ ハンドル) と 2 番目のハンドル (将来のアクティブ ハンドル) の最初の使用の間に以下のアクションが実行されることを保証する必要があります。次に、2 番目のハンドルがアクティブなハンドルになります。 [...]
これらのルールを適用するために、ハンドルが同じプロセスにある必要はありません。
fork()
の後に注意してください アプリケーションは、両方のハンドルにアクセスできる場合、もう一方のハンドルが最初にアクティブなハンドルになる可能性がある状態にあることを確認する必要があります。 [前述の資格の対象となる場合、アプリケーションは] fork()
に備えなければならない アクティブ ハンドルの変更とまったく同じです。 (プロセスの 1 つによって実行される唯一のアクションが exec 関数の 1 つまたは_exit()
の場合 (exit()
ではありません )、そのプロセスでハンドルにアクセスすることはありません。 )
最初のハンドルについては、以下の最初の適用可能な条件が適用されます。[OP の状況に適用されない代替案の非常に長いリスト ...]
- ストリームが読み取りを許可するモードで開かれており、基になる開いているファイルの記述がシーク可能なデバイスを参照している場合、アプリケーションは
fflush()
を実行する必要があります。 、またはストリームを閉じる必要があります。
2 番目のハンドルの場合:
- ファイル オフセットを明示的に変更した関数によって以前のアクティブなハンドルが使用された場合、上記の最初のハンドルで必要な場合を除き、アプリケーションは
lseek()
を実行する必要があります。 またはfseek()
(ハンドルの種類に応じて) 適切な場所に。
したがって、OP のプログラムが親と子の両方で同じストリームにアクセスするために、POSIX は親 fflush()
を要求します。 stdin
フォークする前、そしてその子 fseek()
開始後です。次に、子が終了するのを待った後、親は fseek()
する必要があります ストリーム。ただし、子の exec が失敗することがわかっている場合、すべてのフラッシュとシークの要件は、子に _exit()
を使用させることで回避できます。 exit()
の代わりに (ストリームにアクセスしない) .
POSIX の規定に準拠すると、次の結果が得られます:
<ブロック引用>これらの規則に従う場合、使用されるハンドルの順序に関係なく、実装はアプリケーションが (複数のプロセスから構成されるアプリケーションであっても) 正しい結果をもたらすことを保証する必要があります。シークによって要求されました。
ただし、注目に値するのは、
<ブロック引用>
プログラムの動作に対するあなたの期待が関連する標準によって正当化されていないと単に聞くのは、いくらか不満かもしれませんが、それが本当にすべてです。親プロセスと子プロセスには、共通のオープン ファイル記述の形式で関連する共有データがいくつかあります (それらには個別のハンドルが関連付けられています)。 予期しない (そして定義されていない) 動作については説明しますが、実際に見られる特定の動作や、同じプログラムで見られる別の動作を予測する根拠はありません。