如何保证异步方法线程安全?

Bil*_*eer 6 c# multithreading asynchronous win-universal-app iot

我需要在 Windows 通用应用程序中编写一个方法来写入 SD 卡。在下面的方法中,如何确保两个线程不会尝试同时写入同一个文件?

public async void WriteToCard(string strFileName, IEnumerable<string> listLinesToWrite)
{
    IStorageItem item = await folder.GetItemAsync(strFileName);
    StorageFile file = (StorageFile)item;

    await Windows.Storage.FileIO.WriteLinesAsync(file, listLinesToWrite);
}
Run Code Online (Sandbox Code Playgroud)

Yuv*_*kov 7

您可以保留一个带有 的映射,将ConcurrentDictionary每个文件映射到SemaphoreSlim. 然后,根据您要写入的文件位置获取每个信号量:

private ConcurrentDictionary<string, SemaphoreSlim> fileLocks = new ConcurrentDictionary<string, SemaphoreSlim>();

public async Task WriteToCardAsync(string strFileName, IEnumerable<string> listLinesToWrite)
{
   var semaphoreSlim = fileLocks.GetOrAdd(strFileName, new SemaphoreSlim(1, 1));

   await semaphoreSlim.WaitAsync();
   try
   {
       IStorageItem item = await folder.GetItemAsync(strFileName);
       StorageFile file = (StorageFile)item;

       await Windows.Storage.FileIO.WriteLinesAsync(file, listLinesToWrite);
   }
   finally
   {
       semaphoreSlim.Release();
   }
}
Run Code Online (Sandbox Code Playgroud)

旁注 - 使用async Task而不是async void. 我还将Async后缀添加到方法中。


dca*_*tro 6

您可以使用AsyncEx库,其中包含AsyncLock

假设不会有大量文件名,您可以使用 aConcurrentDictionary将文件名与锁关联 - 否则,字典大小可能会无限增长。

private readonly locks = new ConcurrentDictionary<string, AsyncLock>();

public async void WriteToCard(string strFileName, IEnumerable<string> listLinesToWrite)
{
    var lock = locks.GetOrAdd(strFileName, () => new AsyncLock());

    using (await lock.LockAsync())
    {
        IStorageItem item = await folder.GetItemAsync(strFileName);
        StorageFile file = (StorageFile)item;

        await Windows.Storage.FileIO.WriteLinesAsync(file, listLinesToWrite);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这将只允许在任何时候写入一个*线程*写入一个文件...所以就像在老式的 for 循环中执行它们一样... (2认同)
  • 只要您只对键使用弱引用,就无需担心数百万个文件。ConditionalWeakTable 是一个标准选项,但具有可能成为瓶颈的列表性能(现在可能有标准解决方案没有这个缺点),但至少没有内存泄漏。 (2认同)