reader_writer_lock::scoped_lock and create_task

Somehow reader_writer_lock::scoped_lock is not that easy to use with the different threads created by create_task

I had a function that had to save program settings and for some reason it was called twice in a short period of time.

The function originally looked more or less like this:

auto folder = ApplicationData::Current->LocalFolder;
return create_task(folder->CreateFileAsync(L"program.settings", CreationCollisionOption::ReplaceExisting)).then([this](StorageFile^ file)
{
return doActualSave(file);
}).then([=]()
{
return doSomethingElse();
});

This, however raised WinRT exception that a file is already in use by another process (which wasn't exactly true as the process was the same, just a different thread).

So I first created a reader_writer_lock:

static reader_writer_lock readerWriterLock;
reader_writer_lock::scoped_lock lock(readerWriterLock);
auto folder = ApplicationData::Current->LocalFolder;
return create_task(folder->CreateFileAsync(L"program.settings", CreationCollisionOption::ReplaceExisting)).then([this](StorageFile^ file)
{
return doActualSave(file);
}).then([=]()
{
return doSomethingElse();
});

This, obviously, does not help as the lock is destroyed long before the CreateFileAsync is back. OK, so another try:

static reader_writer_lock readerWriterLock;
readerWriterLock.lock();
auto folder = ApplicationData::Current->LocalFolder;
return create_task(folder->CreateFileAsync(L"program.settings", CreationCollisionOption::ReplaceExisting)).then([this](StorageFile^ file)
{
return doActualSave(file);
}).then([=]()
{
readerWriterLock.Unlock();
return doSomethingElse();
});

Sometimes it worked, but most of the time it didn't as it returned that the object is being held by another writer. Plus it could cause hangs if an exception is thrown between lock/unlock. So I finally ended up with this:

IAsyncAction^ saveProgramSettingsAsync()
{
static reader_writer_lock readerWriterLock;

return create_async([=]() // So we do not wait in GUI thread
{
reader_writer_lock::scoped_lock lock(readerWriterLock);
create_task(saveProgramSettingsInternalAsync()).wait(); // wait() -> So we wait with unlocking
});
}

task<bool> saveProgramSettingsInternalAsync()
{
auto folder = ApplicationData::Current->LocalFolder;
return create_task(folder->CreateFileAsync(L"program.settings", CreationCollisionOption::ReplaceExisting)).then([this](StorageFile^ file)
{
return doActualSave(file);
}).then([=]()
{
readerWriterLock.Unlock();
return doSomethingElse();
});
}