使用FileStream后.SafeFileHandle,我删除对GC.KeepAlive()的调用是安全的吗?

本文关键字:调用 安全 KeepAlive GC SafeFileHandle FileStream 删除 使用 | 更新日期: 2023-09-27 18:11:41

考虑下面的代码,我最近更改为使用FileStream.SafeFileHandle:

public static void FastWrite<T>(FileStream fs, T[] array, int offset, int count) where T: struct
{
    int sizeOfT = Marshal.SizeOf(typeof(T));
    GCHandle gcHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
    try
    {
        uint bytesWritten;
        uint bytesToWrite = (uint)(count * sizeOfT);
        var overlapped = new NativeOverlapped();
        if
        (
            !WriteFile
            (
                fs.SafeFileHandle,
                new IntPtr(gcHandle.AddrOfPinnedObject().ToInt64() + (offset*sizeOfT)),
                bytesToWrite,
                out bytesWritten,
                ref overlapped
            )
        )
        {
            throw new IOException("Unable to write file.", new Win32Exception(Marshal.GetLastWin32Error()));
        }
        Debug.Assert(bytesWritten == bytesToWrite);
        GC.KeepAlive(fs); // <--- Is this really not necessary?
    }
    finally
    {
        gcHandle.Free();
    }
}
[DllImport("kernel32.dll", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool WriteFile
(
    SafeFileHandle       hFile,
    IntPtr               lpBuffer,
    uint                 nNumberOfBytesToWrite,
    out uint             lpNumberOfBytesWritten,
    ref NativeOverlapped lpOverlapped
);

我之前添加了GC.KeepAlive(fs),以确保在Windows API WriteFile()调用返回之前,FileStream不会被垃圾收集。

然而,在改变使用SafeFileHandle代码分析现在告诉我,这是没有必要与warning CA2004: Remove calls to GC.KeepAlive:

如果你正在转换到SafeHandle用法,删除所有对GC的调用。KeepAlive(对象)。

我已经查阅了FileStream.SafeFileHandle的文档,但我不清楚删除对GC.KeepAlive()的调用是否真的是安全的。

移除它一定安全吗?我用对了吗?

还有,谁能给我指出一些关于使用SafeHandle的像样的文档?

使用FileStream后.SafeFileHandle,我删除对GC.KeepAlive()的调用是安全的吗?

使用SafeHandle的要点是,在WriteFile()函数执行时,句柄不会被关闭。这正是你在这里想要达到的。但是请注意,FileStream对象可能仍然是最终确定的。在发布的代码中没有明显的结果。所以FxCop警告是合适的。

请注意使用这样的代码附带的字符串。它不太可能比FileStream.Write()快。但如果没有正确处理边缘条件,就会增加风险。包括使用Overlapped,但不能正确处理重叠的I/O,不要这样做。如果确实打算重叠I/O,那么请检查CLR中超出GCHandle所能做的优化方式的答案。仔细查看一下FileStream的参考源代码,特别关注_isAsync字段和ERROR_NO_DATA和ERROR_INVALID_HANDLE的错误处理。

你也会看到它使用SafeFileHandle和而不是使用GC.KeepAlive(),像FxCop的要求。