fork和(failed)exec后C文件指针改变

我做了制作叉子的程序,我认为孩子不影响父母.

但是文件指针已更改,但我没有对父进行任何更改.

#include 

这输出

I'm one 21500 20
I'm two 21500 -1

我想让两个printf调用之间的文件指针不变.

为什么文件指针会改变,即使execvp失败,我也可以使文件指针不可更改?

最佳答案
感谢Jonathan Leffler指出我们正确的方向.

虽然您的程序在CentOS 7 / GCC 4.8.5 / GLIBC 2.17上不会产生相同的意外行为,但您可能会观察到不同的行为.事实上你的程序的行为是根据POSIX(你依赖fork)来定义的.以下是the relevant section的一些摘录(重点补充):

An open file description may be accessed through a file descriptor,
which is created using functions such as open() or pipe(),or through
a stream,which is created using functions such as fopen() or popen().
Either a file descriptor or a stream is called a “handle” on the open
file description to which it refers; an open file description may have
several handles.

[…]

The result of function calls involving any one handle (the “active
handle”) is defined elsewhere in this volume of POSIX.1-2017,but if
two or more handles are used,and any one of them is a stream,the
application shall ensure that their actions are coordinated as
described below. If this is not done,the result is undefined.

[…]

For a handle to become the active handle,the application shall ensure
that the actions below are performed between the last use of the
handle (the current active handle) and the first use of the second
handle (the future active handle). The second handle then becomes the
active handle. […]

The handles need not be in the same process for these rules to apply.

Note that after a fork(),two handles exist where one existed before.
The application shall ensure that,if both handles can ever be
accessed,they are both in a state where the other could become the
active handle first. [Where subject to the preceding qualification,the] application shall prepare for a fork()
exactly as if it were a change of active handle. (If the only action
performed by one of the processes is one of the exec functions or
_exit() (not exit()),the handle is never accessed in that process.
)

For the first handle,the first applicable condition below applies.
[An impressively long list of alternatives that do not apply to the OP’s situation …]

  • If the stream is open with a mode that allows reading and the underlying open file description refers to a device that is capable of
    seeking,the application shall either perform an fflush(),or the
    stream shall be closed.

For the second handle:

  • If any previous active handle has been used by a function that explicitly changed the file offset,except as required above for the
    first handle,the application shall perform an lseek() or fseek() (as
    appropriate to the type of handle) to an appropriate location.

因此,对于OP的程序来访问父级和子级中的相同流,POSIX要求父级fflush()stdin在分叉之前,并且子级fseek()在启动之后.然后,在等待子进程终止后,父进程必须fseek()流.但是,鉴于我们知道孩子的执行失败,可以通过让孩子使用_exit()(不访问流)而不是exit()来避免所有刷新和搜索的要求.

遵守POSIX的规定会产生以下结果:

When these rules are followed,regardless of the sequence of handles
used,implementations shall ensure that an application,even one
consisting of several processes,shall yield correct results: no data
shall be lost or duplicated when writing,and all data shall be
written in order,except as requested by seeks.

但值得注意的是

It is
implementation-defined whether,and under what conditions,all input
is seen exactly once.

我很欣赏,仅仅听到你对程序行为的期望没有得到相关标准的证明,这可能有点令人不满意,但实际上就是这样.父进程和子进程确实有一些相关的共享数据,这些共享数据采用公共开放文件描述的形式(它们具有相关的单独句柄),这似乎可能是意外(和未定义)行为的载体,但是没有预测您看到的特定行为的基础,以及我在同一程序中看到的不同行为.

相关文章

文章浏览阅读1.8k次,点赞63次,收藏54次。Linux下的目录权限...
文章浏览阅读1.6k次,点赞44次,收藏38次。关于Qt的安装、Wi...
本文介绍了使用shell脚本编写一个 Hello
文章浏览阅读1.5k次,点赞37次,收藏43次。【Linux】初识Lin...
文章浏览阅读3k次,点赞34次,收藏156次。Linux超详细笔记,...
文章浏览阅读6.8k次,点赞109次,收藏114次。【Linux】 Open...