Использование LockFileEX в C#

Можно только расположить экземпляры, которые реализуют интерфейс IDisposable.

Для принуждения мусора сразу собирают к свободному (неуправляемую) память:

GC.Collect();  
GC.WaitForPendingFinalizers();

Это обычно - плохая практика, но существует, например, ошибка в x64-версии платформы.NET, которая заставляет GC вести себя странный в некоторых сценариях, и затем Вы могли бы хотеть сделать это. Я не знаю, была ли ошибка разрешена уже. Кто-либо знает?

Для расположения класса Вы делаете это:

instance.Dispose();

или как это:

using(MyClass instance = new MyClass())
{
    // Your cool code.
}

, который переведет во время компиляции в:

MyClass instance = null;    

try
{
    instance = new MyClass();        
    // Your cool code.
}
finally
{
    if(instance != null)
        instance.Dispose();
}

можно реализовать интерфейс IDisposable как это:

public class MyClass : IDisposable
{
    private bool disposed;

    /// <summary>
    /// Construction
    /// </summary>
    public MyClass()
    {
    }

    /// <summary>
    /// Destructor
    /// </summary>
    ~MyClass()
    {
        this.Dispose(false);
    }

    /// <summary>
    /// The dispose method that implements IDisposable.
    /// </summary>
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// The virtual dispose method that allows
    /// classes inherithed from this one to dispose their resources.
    /// </summary>
    /// <param name="disposing"></param>
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Dispose managed resources here.
            }

            // Dispose unmanaged resources here.
        }

        disposed = true;
    }
}
8
задан ceztko 6 July 2012 в 13:15
поделиться

2 ответа

The following should be "very close" to a good solution. The only part I really don't like is using reflection to access an mscorlib internal method, but that method does an excellent job converting Win32 error codes to an IOException. Since you already have unsafe code for NativeOverlapped*, permissions aren't an issue.

It could probably be further improved by creating a SafeFileLockHandle or similar to provide a lightweight IDisposable object for unlocking the file derived from CriticalFinalizerObject.

    private const uint LOCKFILE_EXCLUSIVE_LOCK = 0x00000002;
    private static readonly Action WinIOError;

    static Win32Native()
    {
        BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
        var winIOErrorMethod = typeof(string).Assembly.GetType("System.IO.__Error").GetMethod("WinIOError", bindingAttr, null, Type.EmptyTypes, null);
        WinIOError = (Action)Delegate.CreateDelegate(typeof(Action), winIOErrorMethod);
    }

    public static void LockFile(SafeFileHandle handle, bool exclusive, long offset, long length, Action action)
    {
        if (handle == null)
            throw new ArgumentNullException("handle");
        if (handle.IsInvalid)
            throw new ArgumentException("An invalid file handle was specified.", "handle");
        if (offset < 0)
            throw new ArgumentOutOfRangeException("The offset cannot be negative.", "offset");
        if (length < 0)
            throw new ArgumentOutOfRangeException("The length cannot be negative.", "length");
        if (action == null)
            throw new ArgumentNullException("action");

        LockFileUnsafe(handle, exclusive, offset, length, action);
    }

    private static unsafe void LockFileUnsafe(SafeFileHandle handle, bool exclusive, long offset, long length, Action action)
    {
        Overlapped overlapped = new Overlapped();
        overlapped.OffsetHigh = (int)(offset >> 32);
        overlapped.OffsetLow = (int)offset;

        IOCompletionCallback callback =
            (errorCode, numBytes, nativeOverlapped) =>
            {
                try
                {
                    action();
                }
                finally
                {
                    Overlapped.Free(nativeOverlapped);
                }
            };

        NativeOverlapped* native = overlapped.Pack(callback, null);
        uint flags = exclusive ? LOCKFILE_EXCLUSIVE_LOCK : 0;
        if (!LockFileEx(handle, flags, 0, (int)length, (int)(length >> 32), native))
        {
            Overlapped.Free(native);
            WinIOError();
        }
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static unsafe extern bool LockFileEx(SafeFileHandle handle, uint flags, uint mustBeZero, int countLow, int countHigh, NativeOverlapped* overlapped);
2
ответ дан 6 December 2019 в 01:40
поделиться

Reflector имеет ответ (а также pinvoke.net и http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/7217a8d3- d36d-43c9-ad4f-ad638a9ac1de есть объявления)

0
ответ дан 6 December 2019 в 01:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: