并发地写入StorageFile

本文关键字:StorageFile 并发 | 更新日期: 2023-09-27 18:04:18

如何在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这样的第三方库,我怎么能仍然保持互斥锁和并发?

并发地写入StorageFile

async操作中,您需要使用 AsyncLock 代替lock

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

AsyncLock msdn, github

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

    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);
                            }
                        }
                    }
                }
            }
        });
    }

我可以使用信号量来解决这个问题。在写入文件之前,我使用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();
}

由于您确实需要使用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");
}

试试这个代码

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();
    }
}