【问题标题】:Writing to StorageFile concurrently同时写入 StorageFile
【发布时间】:2015-07-31 21:26:22
【问题描述】:

如何在 Windows Phone 8.1 中同时将一些文本写入 StorageFile?我尝试在 C# 中实现 lock 提供的互斥锁,但我无法在 lock 块中打开要写入的文件流。

这就是我正在做的:

StorageFile file = await folder.GetFileAsync(logFileName);
// Lock file access object and open filestream for writing.
lock (fileLockObject)
{
    StreamWriter writer = new StreamWriter(await file.OpenStreamForWriteAsync());
    writer.Write(sometext);
}

但是lock 不允许在其主体中进行任何类型的async 操作。在不使用诸如AsyncLock 之类的第三方库的情况下,如何保持互斥锁和并发性?

【问题讨论】:

    标签: c# concurrency windows-phone-8.1


    【解决方案1】:

    async 操作中,您需要使用 AsyncLock 而不是 lock

        private readonly AsyncLock asyncLocker = new AsyncLock();
        .....
        using(await asyncLocker.LockAsync())
        {
           enter code here
        }
    

    AsyncLock msdn, github

    【讨论】:

      【解决方案2】:

      通常在这种情况下,您希望写入尽可能有序,并且您希望将实际写入卸载到另一个单线程。下面是一个简化的示例,但在大多数情况下,您需要对其进行优化以在需要时结束并重新启动线程。

          AutoResetEvent _waitHandle = new AutoResetEvent(false);
          List<string> _writeCache = new List<string>();
          bool _threadRunning = false;
      
          void WriteToFile(string text)
          {
              lock (_writeCache)
              {
                  _writeCache.Add(text);
                  _waitHandle.Set();
      
                  if(_threadRunning)
                  {
                      return;
                  }
                  _threadRunning = true;
              }
      
              Task.Run(async () =>
              {
                  while (true)
                  {
                      _waitHandle.WaitOne();
      
                      StorageFile file = await folder.GetFileAsync(logFileName);
                      using (var f = await file.OpenStreamForWriteAsync())
                      {
                          using (StreamWriter writer = new StreamWriter(await file.OpenStreamForWriteAsync()))
                          {
                              lock (_writeCache)
                              {
                                  while (_writeCache.Count > 0)
                                  {
                                      string s = _writeCache[0];
                                      _writeCache.RemoveAt(0);
                                      writer.Write(s);
                                  }
                              }
                          }
                      }
                  }
              });
          }
      

      【讨论】:

        【解决方案3】:

        我能够使用信号量解决这个问题。在写入文件之前,我使用SlimSemaphore() 获取和释放具有单个资源的信号量。这启用了 await 操作的使用并消除了与 lockmutex 相关的限制,因为您可以在块中运行 await 操作(mutexlock 确实不允许)。

        // define semaphore with only one resource to allocate.
        SemaphoreSlim semaphore = new SemaphoreSlim(1);
        
        // acquire semaphore 
        await semaphore.WaitAsync();
        
        try { // write to file }
        catch { // catch any exception }
        finally
        {
            semaphore.Release();
        }
        

        【讨论】:

        • 是的,这是最好的方法。毫无疑问。
        【解决方案4】:

        由于您确实需要使用lock 语句,您可以尝试:

        using System.Threading.Tasks;
        
        public async Task WriteToFile(string text)
        {
            StorageFile file = await folder.GetFileAsync(logFileName);
        
            lock (fileLockObject)
            {
                Task<Stream> streamTask = file.OpenStreamForWriteAsync();
        
                try
                {
                    streamTask.Wait();
                }
                catch (AggregateException ex)
                {
                     // You may want to handle errors here
                }
        
                if (!streamTask.IsFaulted)
                {
                    using (StreamWriter writer = new StreamWriter(streamTask.Result))
                    {
                        writer.Write(text);
                    }
                }
            }
        }
        

        用法(假设这是一个事件处理程序,否则使用public async Task YourMethod(...)):

        public async void YourMethod()
        {
            // 1. Blocks UI thread
            Task t = WriteToFile("text");
        
            t.Wait();
            // or
            // 2. Does not block UI thread
            await WriteToFile("text");
        }
        

        【讨论】:

        • @AndriiKrupka 根据您的评论编辑帖子。
        【解决方案5】:

        试试这个代码

        public static void WriteLog(string Error)
        {
            using (StreamWriter logfile = new StreamWriter(filePath + "Log.txt", true))
            {
                logfile.WriteLine(DateTime.Now.ToString() + ":" + DateTime.Now.Millisecond.ToString() + " -@: " + Error);
                logfile.Close();
            }
        }
        

        【讨论】:

        • StreamWriter() 需要Stream 类型作为第一个参数。
        • @Flipper 创建一个日志文本文件并将文件路径作为第一个参数,它将获取流。
        猜你喜欢
        • 2022-01-19
        • 1970-01-01
        • 2012-07-06
        • 1970-01-01
        • 1970-01-01
        • 2012-05-04
        • 2010-11-15
        • 2010-11-05
        • 1970-01-01
        相关资源
        最近更新 更多