【问题标题】:How to handle concurrency with StorageFile operations?如何处理 StorageFile 操作的并发性?
【发布时间】:2012-10-03 04:15:43
【问题描述】:

我正在尝试写入文件,但“偶尔”会遇到我认为归结为并发的问题,因为 某些 有时,我会收到 System.UnauthorizedAccessException留言:

访问被拒绝。 (来自 HRESULT 的异常:0x80070005 (E_ACCESSDENIED))

...来自以下:

public async void SubmitChanges()
{
    DataContractSerializer serializer = 
        new DataContractSerializer(typeof(LocalCache<T>));

    StorageFile file = await ApplicationData.Current.LocalFolder
            .CreateFileAsync(GetFileNameForType(), 
                CreationCollisionOption.ReplaceExisting);

    //Occasionally throws here
    using (var fi = await file.OpenTransactedWriteAsync())
    {
        serializer.WriteObject(fi.Stream.AsStreamForWrite(), this);
        await fi.CommitAsync();
    }
}

我只能假设这是由于某种并发性,或者它仍然可以在其他地方读取,但我似乎无法找到等待它可用的方法 - 我通常会lock围绕它,但 await 不允许这样做,那么其他选项是什么?

【问题讨论】:

标签: c# windows-8 microsoft-metro


【解决方案1】:

通常,在上一个操作完成之前,您不会开始下一个操作。

提示:避免async void;请改用async Task。这使您能够知道上一个操作何时完成。

【讨论】:

  • 我已经盯着这个看了很长一段时间,但完全错过了——这是一个漫长的一天,干杯:)
  • 仅供参考,有一个AsyncLock developed by Stephen Toub 和AsyncEx。我只是觉得在这种情况下不需要它。
【解决方案2】:

这里可能会发生很多事情。正如斯蒂芬上面提到的,您的封装方法不会返回任务。这意味着调用 SubmitChanges 的任何方法都使用“即发即弃”模式调用它,并且遵循此调用的代码可以并行运行。这可能不是你想要的。

此外,我注意到您正在使用 StorageFile.OpenTransacted。我以前没有使用过这个,但注释表明 OpenTransacted 仅在支持ReplaceFile 的操作系统上受支持。此功能实际上允许新文件假定旧文件的身份,但我很确定如果旧文件打开,该操作将失败。

我认为在交易文件关闭之前不会尝试交换文件身份,这将发生在 Dispose 上,由于使用而自动发生声明,这是您有时会看到异常的那一行。

我建议您改为返回一个任务,并且我还会考虑使用常规 StorageFile.OpenAsync。

【讨论】:

  • 我使用OpenTransacted 来避免读取文件的半成品副本 - 我可能需要考虑我的对象生命周期,因为它目前可能是触摸 IO 密集型...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-04
  • 1970-01-01
  • 1970-01-01
  • 2017-07-17
  • 2021-06-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多