- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我发现如果我们在关闭文件流之前执行 fork() 操作,打开的文件流将会变得困惑。众所周知,当父进程和子进程想要修改文件流时,可能会发生并发,即竞争条件。但是,即使子进程从未接触过文件流,它仍然具有未定义的行为。我想知道是否有人可以从内核在子进程 fork 和退出阶段如何处理文件流来解释这一点。
下面是一个奇怪行为的快速片段:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
// Open file
FILE* fp = fopen("test.txt", "r");
int count = 0;
char* buffer = NULL;
size_t capacity = 0;
ssize_t line = 0;
while ( (line = getline(&buffer, &capacity, fp)) != -1 ) {
if (line > 0 && buffer[line - 1] == '\n') // remove the end '\n'
buffer[line - 1] = 0;
pid_t pid = fork();
if (pid == 0) {
// fclose(fp); // Magic line here: when you add this, everything is fine
if (*buffer == '2')
execlp("xyz", "xyz", NULL);
else
execlp("pwd", "pwd", NULL);
exit(1);
} else {
waitpid(pid, NULL, 0);
}
count++;
}
printf("Loops: %d\n", count);
return 0;
}
只需将代码复制到新文件中(例如 test.c)。并创建一个包含简单内容的 .txt 文件 test.txt
1
2
3
4
然后运行
$ gcc test.c && ./a.out
文件中有 4 行。循环预计读取每一行并执行 4 次 (1 2 3 4)。我选择让它在第二个循环中执行无效命令“xyz”。然后,你会发现循环实际上执行了6次(1 2 3 4 3 4)!事实是,当执行的所有四个命令都有效时,不会出现任何问题。但如果执行了无效命令,则该命令之后的每个命令都会被执行两次。 (请注意,这种奇怪的行为仅发生在 Linux 机器上,我的 Mac 操作系统运行良好,不确定 Windows 是否如此。所以问题与平台相关?)
看起来每当我 fork() 时,父进程中的文件流不再被 promise 为旧的 fp(非确定性行为),即使我的子进程不触及它。
我找到的临时解决方案是:子进程中的 fclose(fp) 。这将使上述奇怪的行为消失,但在更复杂的条件下,仍然可以观察到其他事情。如果有人能给我一些关于这个问题的见解,我将不胜感激。谢谢
最佳答案
正如评论中所述,您需要在调用 exec 之前关闭打开的文件描述符。
在 this blogpost (第 4 节)有一个简洁的代码示例,您可以使用它来确保所有 fd 都关闭,即使在您并不总是知道当前打开了哪些文件的复杂应用程序中:
for ( i=getdtablesize(); i>2; --i)
close(i); /* close all descriptors */
(稍微修改以保持标准输入、标准输出、标准错误打开)
这有点hacky,但它确实有效。如果您想避免这种情况,还可以在打开的每个文件描述符上设置 O_CLOEXEC
标志。由于使用 fopen 时,您不直接调用 open()
,因此您可以通过向其添加 'e' 标志来完成此操作(当使用 glibc >= 2.7 时):
FILE* fp = fopen("test.txt", "er");
调用 exec*()
时,所有带有此标志的文件描述符都会自动关闭。
关于当 fork() 遇到 fopen() 时的困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52562614/
我想在我的 cpp 函数中调用 fopen,但是,Rcpp 总是提示“没有匹配的函数来调用‘fopen’”。所以完全复制了 https://github.com/hadley/xml2/blob/93
我想在我的 cpp 函数中调用 fopen,但是,Rcpp 总是提示“没有匹配的函数来调用‘fopen’”。所以完全复制了 https://github.com/hadley/xml2/blob/93
我正在使用本教程 http://papermashup.com/caching-dynamic-php-pages-easily/用于缓存页面 /* Heres where you put your
我在 Wordpress 上工作,我对 PHP 几乎一无所知。我正在尝试让带有帖子摘录的滚动条正常工作,但它使用了 fopen() 但它在我客户的主机上已关闭。 $f = fopen( $url, '
我有一个基本程序,旨在复制 bash 的 cp 命令的功能。我正在为 UNIX 和 Windows 开发一个副本。我的 UNIX 版本运行良好,但是,我发现 Windows 不支持 fopen() 的
在我的网站上,用户填写表格进行注册,然后该信息会添加到数据库中。我也试图将信息写入 CSV 文件。到目前为止我的代码给了我这个错误: 警告:fopen() [function.fopen]:第 122
我正在尝试学习 C。函数 Foo 的目标是接受一个字符串,更改其中的一些字符,然后查看是否存在具有该名称的文件。如果存在这样的文件,则在 STDOUT 上打印它的内容。 听起来很简单而且应该很简单,但
我目前有一些未压缩的代码读取文件,它使用以下方法在C++中读取文件 FILE* id = fopen("myfile.dat", "r"); 获得id后,代码的不同部分使用fread、fseek等访问
My last question作为背景。我试图环绕“fopen()”,但 gcc 给了我这个错误,而“remove()”没有问题。 错误:“fopen”的类型冲突fopen(const char *
好的,所以我正在学习 Docker,并且我正在尝试部署一个带有指向我的服务器的子域(其域是从另一个提供商处购买的)的测试应用程序。服务器已经具有非 dockerized Nginx 设置,可以完美地服
我需要在我的系统 verilog 代码中打开一个文件,我需要知道它对我的相对路径才能使用 $fopen。所以首先,我需要知道我的立场。有没有办法知道我当前的目录路径? (通过使用 $display 或
我的网站被一个脚本小子攻击得非常成功。在自动的基础上,一个隐藏的脚本在我的服务器上被访问,导致我所有的 index.php 文件被修改,并在它们的顶部添加一个 iframe(base 64 编码)。
我尝试通过fopen("serial port path", "+w")打开串口 并通过fileno()获取文件描述符。 之后,我调用了 tcsetattr() 但它生成了一个错误,显示 Inappr
在下面的声明中: $handle = fopen('./readme.txt'); $handle 是什么变量?是 bool 值还是什么? 在运行这两个不同的语句后我有疑问: if($handle)
我是一名 PHP 学习者,我正在处理文件,但我无法在自己的服务器中打开文件,因为出现“权限被拒绝”错误。我正在使用 fopen()功能:fopen('file.txt', 'r+'); 我在 Cent
我需要打开一个文件,替换一些内容(12345 为 77348)并保存。据我所知 $cookie_file_path=$path."/cookies/shipping-cookie".$unique;
我有一个巨大的二进制文件,有 2148181087 字节 (> 2gb) 我正在尝试执行 fopen (file, "r") 但失败了 Can not open: xyz file (Value to
我的桌面上有一个名为 fun 的文本文件,但是当我通过时: FILE* fp; if((fp = fopen("/Users//Desktop/fun", "r")) == NULL) { p
我有一个名为 denem.txt 的文件并且有内容 123456789 123456789 123456789 当我们以“a+b”模式打开文件时,PHP 应该将指针指向文件末尾,这意味着当我尝试使用
我想知道是否有人可以通过 Matlab fopen 命令阐明以下问题: >> [stat myjob] = unix('echo $PBS_NODEFILE'); % gets PBS file na
我是一名优秀的程序员,十分优秀!