在同一个文件上同时以读取模式打开两个 FILE 句柄
Opening two FILE handles in read mode, on the same file, simultaneously
我正在编写一个程序,它接收读取文件的请求,然后通过 TCP 套接字(HTTP 服务器)发送它们的内容。跨多个线程同时为客户端提供服务,我注意到两个客户端完全有可能同时请求同一个文件。
我希望,如果线程 1 调用 fopen(path,"rb");
,然后线程 2 也调用 fopen(path,"rb"); // Same path.
,因为这两个线程都在 path
以读取模式打开文件,所以如果路径有效,两个调用都应该成功。
但是我确实担心在线程 1 打开 FILE*
之后线程 2 对 fopen
的调用将 return 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');
};
with testfile.txt
containing 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
是否仍然有效?
- 这会不会有导致未定义行为的危险?
- 这会不会有导致数据竞争的危险?
一次从多个文件句柄以只读方式打开同一个文件不是问题;它将按预期可靠地工作。由于文件中没有数据被修改,并且由于所有瞬态数据(例如缓冲数据、当前查找位置)都保存在 FILE
结构本身中(并且每个线程都有自己的 separate/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?
没有
我正在编写一个程序,它接收读取文件的请求,然后通过 TCP 套接字(HTTP 服务器)发送它们的内容。跨多个线程同时为客户端提供服务,我注意到两个客户端完全有可能同时请求同一个文件。
我希望,如果线程 1 调用 fopen(path,"rb");
,然后线程 2 也调用 fopen(path,"rb"); // Same path.
,因为这两个线程都在 path
以读取模式打开文件,所以如果路径有效,两个调用都应该成功。
但是我确实担心在线程 1 打开 FILE*
之后线程 2 对 fopen
的调用将 return 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');
};
with testfile.txt
containing 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
是否仍然有效?- 这会不会有导致未定义行为的危险?
- 这会不会有导致数据竞争的危险?
一次从多个文件句柄以只读方式打开同一个文件不是问题;它将按预期可靠地工作。由于文件中没有数据被修改,并且由于所有瞬态数据(例如缓冲数据、当前查找位置)都保存在 FILE
结构本身中(并且每个线程都有自己的 separate/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?
没有