You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 15:54:53