这是否正确使用互斥锁以避免并发修改文件?

时间:2014-04-15 09:21:20

标签: c# silverlight windows-phone-7 windows-phone-8 mutex

我希望能够将写入文件的代码放入互斥锁中,以避免对文件进行任何并发修改。但是,我只希望将具有特定名称的文件作为关键部分而不是其他文件。这段代码会按预期工作还是我错过了什么?

private async static void StoreToFileAsync(string filename, object data)
    {
        IsolatedStorageFile AppIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication();
        if (IsolatedStorageFileExist(filename))
        {
            AppIsolatedStorage.DeleteFile(filename);
        }
        if (data != null)
        {
            string json = await Task.Factory.StartNew<string>(() => JsonConvert.SerializeObject(data));
            if (!string.IsNullOrWhiteSpace(json))
            {
                byte[] buffer = Encoding.UTF8.GetBytes(json);
                Mutex mutex = new Mutex(false, filename);
                mutex.WaitOne();
                IsolatedStorageFileStream ISFileStream = AppIsolatedStorage.CreateFile(filename);
                await ISFileStream.WriteAsync(buffer, 0, buffer.Length);
                ISFileStream.Close();
                mutex.ReleaseMutex();
            }
        }
    }

编辑1:或者我应该将异步写入替换为同步写入并作为单独的任务运行吗?

await Task.Factory.StartNew(() =>
                    {
                        if (!string.IsNullOrWhiteSpace(json))
                        {
                            byte[] buffer = Encoding.UTF8.GetBytes(json);
                            lock (filename)
                            {
                                IsolatedStorageFileStream ISFileStream = AppIsolatedStorage.CreateFile(filename);
                                ISFileStream.Write(buffer, 0, buffer.Length);
                                ISFileStream.Close();
                            }
                        }
                    });  

2 个答案:

答案 0 :(得分:3)

在一般情况下,使用带有异步代码的Mutex是错误的。通常情况下,我说你应该使用类似AsyncLock from my AsyncEx library的内容,如果你想为每个文件单独锁定,那么你需要一本字典或其他类似的字典。

但是,如果始终从UI线程调用您的方法,那么它将起作用。它不是很有效,但它会起作用。

答案 1 :(得分:2)

你应该改进一些事情:

  • 在Mutex内部运行异步代码并不好,因为同一个线程应该创建并释放Mutex。当不是从UI线程调用时,您可能会遇到异常。
  • filename不是互斥体的好名字 - 它是全局对象(在所有进程中),所以它应该是唯一的。
  • 你应该处理你的Mutex,并在finally子句中删除它(如果你遇到异常会怎样?) - BTW here is a good pattern
  • 你应该/必须Dispose IsolatedFileStream
  • 您还应该考虑无限等待是一个不错的选择
  • 如果您没有访问文件amopng进程(Bacground Agents,其他应用程序),那么您可以使用lockSemaphoreSlim

private async static void StoreToFileAsync(string filename, object data)
{
    using (IsolatedStorageFile AppIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
    {
        if (IsolatedStorageFileExist(filename))
            AppIsolatedStorage.DeleteFile(filename);
        if (data != null)
        {
            string json = await Task.Factory.StartNew<string>(() => JsonConvert.SerializeObject(data));
            if (!string.IsNullOrWhiteSpace(json)) await Task.Run(() =>
                {
                    byte[] buffer = Encoding.UTF8.GetBytes(json);
                    using (Mutex mutex = new Mutex(false, filename))
                    {
                        try
                        {
                            mutex.WaitOne();
                            using (IsolatedStorageFileStream ISFileStream = AppIsolatedStorage.CreateFile(filename))
                                ISFileStream.Write(buffer, 0, buffer.Length);
                        }
                        catch { }
                        finally { mutex.ReleaseMutex(); }
                    }
                });
        }
    }
}

编辑:从Mutex中删除了异步调用 - 因为它不会从UI线程调用时会导致问题。