Reputation: 10201
When writing a file using the Windows Runtime, all methods are asynchronous. Is it possible to ensure that my file access and writes are done sequentially in this scenario?
For example, if I have a logging class that may be called from multiple other asynchronous and possibly parallel code, how might I ensure the logger actually writes to a file synchronously?
Due to using async/await, I can't just put a lock around the file access like:
lock (locker)
{
var storageFile = await GetStorageFileAsync();
await FileIO.AppendTextAsync(storageFile, text);
}
I was wondering if a BufferBlock from the Dataflow TPL would work in this scenario to serialize the writing, but I'm unsure of exactly how to set that up. I think it would look like:
static readonly BufferBlock<string> LogBuffer = new BufferBlock<string>();
public async static Task LogAsync(string message)
{
LogBuffer.Post(message);
string messageToWrite;
while (LogBuffer.TryReceive(out messageToWrite))
{
var storageFile = await GetStorageFileAsync();
await FileIO.AppendTextAsync(storageFile, messageToWrite);
}
}
It's likely that I'm mixing up asynchronous and multi-threaded programming, but I thought when using Tasks that you can't be sure which thread you code will be called on. In this case, I want to ensure only one thread can access the file at a time. Am I heading in the right direction?
Upvotes: 1
Views: 90
Reputation: 457017
What you want is synchronized asynchronous code. Async code by default is sequential (if you await
one operation, then the method will not continue until that operation is completed); you want it to be synchronized. Not "synchronous", either; you still want it to be asynchronous.
You can just use SemaphoreSlim
as an async
-compatible lock
to synchronize asynchronous code:
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1);
...
await _semaphore.WaitAsync();
try
{
var storageFile = await GetStorageFileAsync();
await FileIO.AppendTextAsync(storageFile, text);
}
finally
{
_semaphore.Release();
}
That said, you may prefer an ActionBlock
if you want the rest of the code to continue immediately after queueing the write instead of (asynchronously) waiting for the write to complete.
Upvotes: 3