Windows中CloseHandle为何会阻塞至FlushFileBuffers完成?
Windows多线程文件操作:CloseHandle阻塞等待FlushFileBuffers完成
我正在开发一款Windows程序,需要在将数据缓冲区刷新(同步)到磁盘的同时读取该文件。为此用了两个线程:一个通过FlushFileBuffers调用刷新数据,另一个负责打开文件、同步调用ReadFile读取后关闭文件。但发现读取线程的CloseHandle调用会阻塞,直到FlushFileBuffers完成,导致两个操作串行执行。
我希望文件关闭操作能以非阻塞方式和磁盘刷新同时进行,因为这是多线程程序且两个线程没有明显依赖,完全无法理解为什么会出现等待情况。
简化示例代码(省略错误处理)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <windows.h> #include <time.h> volatile int done_a = 0; volatile int done_b = 0; unsigned long long file_size; long unsigned int reader_func(void *unused) { DWORD err; HANDLE h; srand(time(NULL)); puts("reading randomly in file"); unsigned char buf; while (!done_a) { clock_t begin = clock(); h = CreateFileA("test.bin", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); unsigned long long randVal = (((unsigned long long)rand() << 60) | ((unsigned long long)rand() << 45) | ((unsigned long long)rand() << 30) | ((unsigned long long)rand() << 15) | ((unsigned long long)rand() << 0)) % file_size; printf("reading at %llu\n", randVal); SetFilePointerEx(h, (LARGE_INTEGER){.QuadPart=randVal}, NULL, FILE_BEGIN); ReadFile(h, &buf, 1, NULL, NULL); puts("closing file handle"); CloseHandle(h); double time_spent = (double)(clock() - begin) / CLOCKS_PER_SEC; printf("read took %f\n", time_spent); Sleep(250); } done_b = 1; return 0; } int main(int argc, char **argv) { char *endptr; if (argc > 1) file_size = strtoull(argv[1], &endptr, 10); else return 1; // Open file DWORD err; HANDLE h = CreateFileA("test.bin", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // Size file to given size SetFilePointerEx(h, (LARGE_INTEGER){.QuadPart=file_size}, NULL, FILE_BEGIN); SetEndOfFile(h); SetFilePointerEx(h, (LARGE_INTEGER){0}, NULL, FILE_BEGIN); // Write some data to file puts("writing to file"); char buf[4096]; memset(buf, 0xa5, 4096); for (DWORD i = 0; i < file_size; i += 4096) WriteFile(h, buf, 4096, NULL, NULL); // spawn thread to continuously read from block puts("spawning reader thread"); CreateThread(NULL, 0, reader_func, NULL, 0, NULL); Sleep(250); // FlushFileBuffers puts("flushing file buffers"); clock_t begin = clock(); FlushFileBuffers(h); double time_spent = (double)(clock() - begin) / CLOCKS_PER_SEC; printf("FlushFileBuffers took %f to finish\n", time_spent); // signal completion puts("done"); done_a = 1; CloseHandle(h); while (!done_b); puts("done"); DeleteFileA("test.bin"); return 0; }
测试现象
使用较大参数运行(比如a.exe 1073741824,可根据磁盘读写速度调整),会看到CloseHandle调用耗时和FlushFileBuffers相近,因为它会等待后者完成才返回。我通过SysInternals Process Monitor观察到了这个行为。
我在Windows 10、11系统的HDD和SSD上都测试过,问题始终存在;甚至Linux下的Wine环境也有这个现象。预期行为应该是CloseHandle立即返回而非等待。我还发现CreateFile、ReadFile等其他库调用也存在类似阻塞行为,但更难复现。
环境信息
- 操作系统:Windows 10
- 编译器:x86_64-w64-mingw32-gcc 13
- 磁盘:SK hynix BC511 NVMe SSD
内容的提问来源于stack exchange,提问作者Conexn
相关产品推荐
相关产品推荐

