c#用于I / O访问的动态锁定

时间:2016-03-11 15:26:50

标签: c# thread-safety locking

我有一个名为DownloadFileAsync的方法,用于下载文件,另一个名为GetLocalFilePathAsync,用于返回文件路径。

我的问题是调用GetLocalFilePathAsync而DownloadFileAsync未完成导致零字节文件和错误。

我尝试根据这个问题实现动态锁定: Creating Dynamic Locks at Runtime in ASP.NET

这是我的代码。

public static class DynamicLock
{
    private static Dictionary<string, AsyncLock> LockList = new Dictionary<string, AsyncLock>();
    private static readonly object lockDic = new AsyncLock();

    public static void LockOnValue(string lockKey)
    {
        lock (lockDic)
        {
            AsyncLock obj = null;
            if (!LockList.TryGetValue(lockKey, out obj))
            {
                obj = new AsyncLock();
                LockList.Add(lockKey, obj);
            }
            Monitor.Enter(obj);
            //System.Diagnostics.Debug.WriteLine($"LockList count: {LockList.Count} {lockKey} locked,  Value = {obj}");
        }
    }

    public static void UnlockOnValue(string lockKey)
    {
        Monitor.Exit(LockList[lockKey]);
    }
}

public static async Task<string> GetLocalFilePathAsync(string itemId, string fileName)
    {
        var lockKey = $"{itemId}_{fileName}";
        DynamicLock.LockOnValue(lockKey);
        try
        {
            System.Diagnostics.Debug.WriteLine($"PATH ACCESS FILE {lockKey}");
            if (string.IsNullOrEmpty(itemId) || string.IsNullOrEmpty(fileName))
                return null;
            IPlatform platform = DependencyService.Get<IPlatform>();
            string recordFilesPath = Path.Combine(await platform.GetFilesPathAsync(), itemId);
            var checkExists = await FileSystem.Current.LocalStorage.CheckExistsAsync(recordFilesPath);
            if (checkExists == ExistenceCheckResult.NotFound)
                return null;
            return Path.Combine(recordFilesPath, fileName);
        }
        catch
        {
            throw;
        }
        finally
        {
            DynamicLock.UnlockOnValue(lockKey);
            System.Diagnostics.Debug.WriteLine($"PATH UNLOCK {lockKey}");
        }
    }

public static async Task DownloadFileAsync<T>(IMobileServiceSyncTable<T> table, MobileServiceFile file)
    {
        var lockKey = $"{file.ParentId}_{file.Name}";
        DynamicLock.LockOnValue(lockKey);
        try
        {
            System.Diagnostics.Debug.WriteLine($"DOWNALOAD FILE {lockKey}");
            var platform = DependencyService.Get<IPlatform>();
            await platform.DownloadFileAsync(table, file);
        }
        catch
        {
            throw;
        }
        finally
        {
            DynamicLock.UnlockOnValue(lockKey);
            System.Diagnostics.Debug.WriteLine($"DOWNALOAD UNLOCK {lockKey}");
        }
    }

来自日志:

DOWNALOAD FILE e7152b72-adf6-4615-b5f9-e77e3ca4345b_IMG_20160219_101743.jpg

路径访问文件e7152b72-adf6-4615-b5f9-e77e3ca4345b_IMG_20160219_101743.jpg

PATH UNLOCK e7152b72-adf6-4615-b5f9-e77e3ca4345b_IMG_20160219_101743.jpg

ERROR

因此,在DownloadFileAsyn发布锁定之前执行GetLocalFilePathAsync。

我错过了什么?

韩国社交协会

1 个答案:

答案 0 :(得分:1)

在这里写我的问题让我重新思考它,下面的内容似乎有效(尽管我还是要彻底测试)。

public static class DynamicLock
{
    private static Dictionary<string, AsyncLock> LockList = new Dictionary<string, AsyncLock>();
    private static readonly object lockDic = new AsyncLock();

    public static async Task<T> LockOnKey<T>(string lockKey, Func<Task<T>> criticalFunc)
    {
        AsyncLock obj = null;
        lock (lockDic)
        {

            if (!LockList.TryGetValue(lockKey, out obj))
            {
                obj = new AsyncLock();
                LockList.Add(lockKey, obj);
            }
        }
        using (var releaser = await obj.LockAsync().ConfigureAwait(false))
        { 
            return await criticalFunc();
        }
    }
}