Как обработать параллелизм с операциями StorageFile?

Я пытаюсь записать файл, но "иногда" я сталкиваюсь с проблемами, которые, по моему мнению, сводятся к параллелизму, так как иногда я получаю 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 так каковы другие варианты?

2 ответа

Решение

Обычно вы просто не начинаете следующую операцию, пока предыдущая операция не будет завершена.

Совет: избегайте async void; использование async Task вместо. Это позволяет вам знать, когда предыдущая операция завершена.

Есть много вещей, которые могут происходить здесь. Как уже упоминал Стивен, ваш метод инкапсуляции не возвращает задачу. Это означает, что любой метод, вызывающий метод SubmitChanges, вызывает его с шаблоном "запусти и забудь", и код, следующий за этим вызовом, может выполняться параллельно. Это, вероятно, не то, что вы хотите.

Кроме того, я заметил, что вы используете StorageFile.OpenTransacted. Я не использовал это раньше, но заметки указывают, что OpenTransacted поддерживается только в операционных системах, которые поддерживают ReplaceFile. Эта функция буквально позволяет новому файлу принимать идентичность старого файла, но я уверен, что операция не удастся, если старый файл открыт.

Я не думаю, что попытка обмена идентификаторами файлов будет происходить до тех пор, пока не будет закрыт транзакционный файл, что происходит при Dispose, что происходит автоматически из-за оператора using, который является строкой, в которой вы иногда видите исключение.

Я бы порекомендовал вам вернуть задачу, а также рассмотреть возможность использования обычного StorageFile.OpenAsync.

Другие вопросы по тегам