我正在编写一个程序,它接收读取文件的请求,然后通过 TCP 套接字(HTTP 服务器)发送它们的内容。跨多个线程同时为客户端提供服务,我注意到两个客户端完全有可能同时请求同一个文件。
我希望如果线程 1 调用 fopen(path,"rb");
然后线程 2 也调用 fopen(path,"rb");//相同的路径。
,因为这两个都在读取模式下打开位于 path
的文件,如果路径有效,两个调用都应该成功。
但是我确实担心,在线程 1 打开一个 FILE*
之后,线程 2 对 fopen
的调用将返回 NULL
,因为已经存在作为一个打开的文件句柄,在我的 HTTP 服务器的上下文中,这将导致客户端错误地接收到 404 Not Found
错误页面,而不是请求的资源,这当然不是期望的结果.
我确信有一些方法可以在这些线程之间同步访问或共享文件句柄,但为了简单起见,我希望能够避免实现这些更复杂的机制。
在带有 MinGW-w64 的 Windows 上,我发现这段代码:
#include <stdio.h>
int main ()
{
FILE* handle1 = fopen("testfile.txt","rb");
FILE* handle2 = fopen("testfile.txt","rb");
printf("%llX\n",handle1);
printf("%llX\n",handle2);
char buf [8];
for (int i = 0; i < 8; i++) buf[i] = 'X';
fread(buf,1,8,handle1);
for (int i = 0; i < 8; i++) putchar(buf[i]);
putchar('\n');
for (int i = 0; i < 8; i++) buf[i] = 'X';
fread(buf,1,8,handle2);
for (int i = 0; i < 8; i++) putchar(buf[i]);
putchar('\n');
};
testfile.txt
包含 File Contents
产生以下输出:
7FFE2439FA90
7FFE2439FAC0
File Con
File Con
...这就是我想要它做的。
但是我想知道这种行为是否是标准的,或者只是因为有关 Windows 或我的代码链接到的标准库实现的某些原因才按我的意愿行事。
如果它是标准的(或者,至少普遍到可以在 Windows 和 Linux 之间移植)行为,我就可以避免让我的代码变得比它需要的更复杂。但是,当然,如果它不是可移植的行为,那么我确实需要弄清楚一些事情。
长话短说:
如果“file.txt”是一个有效的路径,那么在下面的代码中:
char* path = "file.txt";
FILE* file1 = fopen(path,"r");
FILE* file2 = fopen(path,"r");
跨各种平台,
file2 != file1
会得到保证吗?file2 != NULL
会得到保证吗?file1
是否仍然有效?- 这会不会有导致未定义行为的危险?
- 这会不会有导致数据竞争的危险?
最佳答案
一次从多个文件句柄以只读方式打开同一个文件不是问题;它将按预期可靠地工作。由于文件中没有数据被修改,并且由于所有 transient 数据(例如缓冲数据、当前查找位置)都保存在 FILE
结构本身中(每个线程都有自己的单独/私有(private)的 FILE
结构),没有竞争条件。
Will file2 != file1 be guaranteed?
是的。
Will file2 != NULL be guaranteed?
是的(假设文件在两次调用之间没有被删除或重命名,当然 :))
Will file1 still be valid?
是的。
Will this have a danger of causing undefined behavior?
没有。
Will this have a danger of causing a data race?
没有。
关于c - 在同一个文件上同时以读取模式打开两个 FILE 句柄,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54507454/