После использования FileStream.SafeFileHandle безопасно ли мне удалять вызов GC.KeepAlive()?
Рассмотрим следующий код, который я недавно изменил, чтобы использовать 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)
чтобы убедиться, что FileStream не будет собирать мусор до окончания работы Windows API WriteFile()
звонок вернулся.
Однако после перехода на использование SafeFileHandle
Анализ кода теперь говорит мне, что это не нужно с warning CA2004: Remove calls to GC.KeepAlive
:
Если вы переходите на использование SafeHandle, удалите все вызовы GC.KeepAlive (объект).
Я ознакомился с документацией по FileStream.SafeFileHandle
но мне неясно, действительно ли безопасно для меня убрать вызов GC.KeepAlive()
,
Это определенно безопасно удалить? И правильно ли я его использую?
Кроме того, кто-нибудь может указать мне какую-нибудь приличную документацию по использованию SafeHandle?
1 ответ
Смысл использования SafeHandle заключается в том, что дескриптор не будет закрыт во время выполнения функции WriteFile(). Что действительно то, чего вы хотите достичь здесь. Однако обратите внимание, что объект FileStream все еще может быть завершен. Там нет очевидных последствий от того, что происходит в размещенном коде. Так что предупреждение FxCop уместно.
Обратите внимание на строки, связанные с использованием кода, подобного этому. Маловероятно, что это будет быстрее, чем FileStream.Write(). Но вы добавляете риск, не имея должного отношения к граничным условиям. Включая использование перекрывающегося, но неправильно обработанного перекрывающегося ввода-вывода, не делайте этого. Если перекрывающийся ввод-вывод на самом деле предназначен, проверьте этот ответ на предмет того, как он оптимизирован в CLR, помимо того, что может сделать GCHandle. Внимательно ознакомьтесь с исходным кодом Reference Source для FileStream, особенно обратите внимание на поле _isAsync и обработку ошибок для ERROR_NO_DATA и ERROR_INVALID_HANDLE.
И вы также увидите это, используя SafeFileHandle и не используя GC.KeepAlive(), как того требует FxCop.