Это относится к http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx , http://winrtstoragehelper.codeplex.com/ , магазину приложений Windows 8 и .net 4.5
Вот мой взгляд на это:
Функция языка async / await делает многие вещи довольно простыми, но она также представляет сценарий, с которым редко сталкивались до того, как стало так легко использовать асинхронные вызовы: reentrance.
Это особенно верно для обработчиков событий, потому что для многих событий вы не имеете никакого представления о том, что происходит после того, как вы вернетесь из обработчика событий. В действительности может произойти то, что асинхронный метод, который вы ожидаете в первом обработчике событий, вызывается из другого обработчика событий, все еще находящегося в том же потоке.
Вот реальный сценарий, с которым я столкнулся в приложении Windows 8 App Store: у моего приложения есть два фрейма: вход и выход из фрейма, я хочу загрузить / сохранить некоторые данные в файл / хранилище. События OnNavigatedTo / From используются для сохранения и загрузки. Сохранение и загрузка выполняются с помощью некоторой функции асинхронной утилиты (например, http://winrtstoragehelper.codeplex.com/ ). При переходе от кадра 1 к кадру 2 или в другом направлении вызывается и ожидается асинхронная загрузка и безопасные операции. Обработчики событий становятся асинхронными, возвращая void => их нельзя ожидать.
Однако первая операция открытия файла (позволяет говорить: внутри функции сохранения) утилиты также асинхронна, и поэтому первое ожидание возвращает управление платформе, которая через некоторое время вызывает другую утилиту (загрузку) через второй обработчик событий. Теперь загрузка пытается открыть тот же файл, и если файл уже открыт для операции сохранения, происходит сбой с исключением ACCESSDENIED.
Минимальное решение для меня - обеспечить доступ к файлу через использование и AsyncLock.
private static readonly AsyncLock m_lock = new AsyncLock();
...
using (await m_lock.LockAsync())
{
file = await folder.GetFileAsync(fileName);
IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read);
using (Stream inStream = Task.Run(() => readStream.AsStreamForRead()).Result)
{
return (T)serializer.Deserialize(inStream);
}
}
Обратите внимание, что его блокировка в основном блокирует все файловые операции для утилиты всего одной блокировкой, которая неоправданно сильна, но прекрасно работает для моего сценария.
Вот мой тестовый проект: приложение магазина приложений для Windows 8 с некоторыми тестовыми вызовами для исходной версии http://winrtstoragehelper.codeplex.com/ и моей модифицированной версии, в которой используется AsyncLock от Стивена Тауба http: //blogs.msdn. com / b / pfxteam / archive / 2012/02/12 / 10266988.aspx .
Могу ли я также предложить эту ссылку:
http://www.hanselman.com/blog/ComparingTwoTechniquesInNETAsynchronousCoordinationPrimitives.aspx