Це стосується http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx , http://winrtstoragehelper.codeplex.com/ , магазину додатків Windows 8 та .net 4.5
Ось мій кут на це:
Функція мови асинхронізації / очікування робить багато речей досить легкими, але вона також вводить сценарій, з яким рідко стикалися, до того, як було так просто використовувати виклики асинхронізації: повторне використання.
Особливо це стосується обробників подій, оскільки для багатьох подій у вас немає поняття про те, що відбувається після повернення з обробника подій. Одне, що може насправді трапитися, це те, що метод асинхронізації, якого ви очікуєте в обробці першого події, викликається від іншого обробника подій, який все ще знаходиться в тій самій ниті.
Ось справжній сценарій, який я натрапив на додаток у магазині Windows 8 App: У моїй програмі є два кадри: входження та вихід із кадру, я хочу завантажити / зберегти деякі дані для файлу / зберігання. Для збереження та завантаження використовуються події OnNavigatedTo / From. Збереження та завантаження виконується деякою функцією утиліти async (наприклад, 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 від Stephen Toub http: //blogs.msdn. com / b / pfxteam / archive / 2012/02/12 / 10266988.aspx .
Чи можна також запропонувати це посилання:
http://www.hanselman.com/blog/ComparingTwoTechniquesInNETAsynchronousCoordinationPrimitive.aspx