How to handle concurrency with StorageFile operations?

只谈情不闲聊 提交于 2019-12-11 10:28:46

问题


I'm attempting to write to a file but "occasionally" I run into issues that I think are down to concurrency, as some of the time, I'm getting a System.UnauthorizedAccessException with message:

Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

...from the following:

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();
    }
}

I can only assume that this is down to some concurrency, or it being still open for read somewhere else, but I can't seem to find a way to wait for it to become available - I'd normally lock around it, but this is not allowed with await so what are the other options?


回答1:


Usually, you just don't start the next operation until the previous operation is complete.

Tip: avoid async void; use async Task instead. That enables you to know when the previous operation is complete.




回答2:


There are a number of things that could be happening here. As Stephen mentioned above, your encapsulating method does not return a task. This means that whatever method is calling SubmitChanges is calling it with a "fire and forget" pattern and code that follows this call can be run in parallel. This is probably not what you want.

In addition, I notice you're using StorageFile.OpenTransacted. I've not used this before but the notes indicate OpenTransacted is only supported on operating systems that support ReplaceFile. This feature literally allows the new file to assume the identity of the old file, but I'm pretty sure that operation would fail if the old file is open.

I don't think the attempt to swap file identities would happen until the transacted file is closed, which would happen on Dispose, which happens automatically due to the using statement, which is the line you're sometimes seeing the exception.

I would recommend you return a Task instead and I would also consider using the regular StorageFile.OpenAsync.



来源:https://stackoverflow.com/questions/12697178/how-to-handle-concurrency-with-storagefile-operations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!