You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Microsoft IoT的树莓派UWP应用线程安全C#日志器开发求助

线程安全的UWP日志器实现方案(适配树莓派Microsoft IoT)

我来帮你解决这个问题!在UWP(尤其是树莓派IoT环境下)实现线程安全的日志器,核心痛点就是异步文件操作和同步锁的冲突——毕竟lock块里确实没法用await。不过我们可以换个思路,用消息队列+后台异步消费的方式来绕开这个矛盾,下面是具体的实现方案:

核心思路

直接在lock里调用异步文件API行不通,因为await会释放当前线程,导致锁失去作用。我们可以:

  • 用线程安全的队列(ConcurrentQueue)缓存所有日志请求,让日志方法只负责快速入队,不等待写入完成
  • 启动一个后台异步任务,持续从队列中取出消息并异步写入文件
  • 用信号量(SemaphoreSlim)确保后台任务只会启动一次,避免重复消费

完整实现代码

下面是一个可直接复用的单例日志器:

using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Windows.Storage;

public class Logger
{
    // 单例实例
    private static readonly Lazy<Logger> _instance = new Lazy<Logger>(() => new Logger());
    public static Logger Instance => _instance.Value;

    // 线程安全的日志消息队列
    private readonly ConcurrentQueue<string> _logQueue = new ConcurrentQueue<string>();
    // 控制后台任务的信号量,确保只启动一次
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
    // 日志文件对象
    private StorageFile _logFile;

    private Logger()
    {
        // 构造函数不做异步初始化,留到第一次日志写入时处理
    }

    /// <summary>
    /// 写入日志
    /// </summary>
    /// <param name="message">日志内容</param>
    /// <param name="level">日志级别(可选)</param>
    public void Log(string message, string level = "INFO")
    {
        // 格式化日志:时间戳 + 级别 + 消息
        var formattedLog = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{level}] {message}";
        
        // 入队,ConcurrentQueue本身线程安全,无需额外lock
        _logQueue.Enqueue(formattedLog);
        
        // 启动后台处理任务(确保只启动一次)
        _ = ProcessQueueAsync();
    }

    /// <summary>
    /// 后台异步处理队列中的日志
    /// </summary>
    private async Task ProcessQueueAsync()
    {
        // 尝试获取信号量,如果已经有任务在运行则直接返回
        if (!await _semaphore.WaitAsync(0))
        {
            return;
        }

        try
        {
            // 初始化日志文件(第一次运行时创建)
            if (_logFile == null)
            {
                _logFile = await GetLogFileAsync();
            }

            // 循环处理队列中的消息
            while (_logQueue.TryDequeue(out string logMessage))
            {
                try
                {
                    // 异步写入文件,AppendTextAsync是UWP的异步API
                    await FileIO.AppendTextAsync(_logFile, logMessage + Environment.NewLine);
                }
                catch (Exception ex)
                {
                    // 写入失败时做降级处理,输出到调试窗口
                    System.Diagnostics.Debug.WriteLine($"日志写入失败:{ex.Message}");
                }
            }
        }
        finally
        {
            // 释放信号量,允许下次任务启动
            _semaphore.Release();
        }
    }

    /// <summary>
    /// 获取或创建日志文件
    /// </summary>
    private async Task<StorageFile> GetLogFileAsync()
    {
        var localFolder = ApplicationData.Current.LocalFolder;
        try
        {
            return await localFolder.GetFileAsync("app.log");
        }
        catch (FileNotFoundException)
        {
            return await localFolder.CreateFileAsync("app.log", CreationCollisionOption.OpenIfExists);
        }
    }

    /// <summary>
    /// 强制刷新队列中的剩余日志(比如应用退出时调用)
    /// </summary>
    public async Task FlushAsync()
    {
        // 等待当前处理任务完成,然后再处理一次队列
        await ProcessQueueAsync();
    }
}

关键细节说明

  • 线程安全性:ConcurrentQueue本身支持多线程并发读写,无需额外加锁,Log方法可以安全地被多个线程调用
  • 异步处理:后台任务ProcessQueueAsync负责所有异步文件操作,不会阻塞调用Log的线程
  • 异常防护:写入日志时的异常被捕获,避免单个日志写入失败导致整个后台任务崩溃
  • 应用收尾:在UWP应用的Suspending事件中调用await Logger.Instance.FlushAsync(),确保退出前所有未写入的日志都被处理:
    private async void OnSuspending(object sender, SuspendingEventArgs e)
    {
        var deferral = e.SuspendingOperation.GetDeferral();
        await Logger.Instance.FlushAsync();
        deferral.Complete();
    }
    

树莓派IoT环境的额外注意事项

  • 权限问题:UWP应用默认拥有对ApplicationData.Current.LocalFolder的访问权限,不需要额外在Package.appxmanifest中声明权限
  • 日志滚动:如果日志量较大,可以扩展代码实现按文件大小或日期分割日志(比如当文件超过10MB时创建新文件)
  • 性能优化:ConcurrentQueue的入队操作非常轻量,不会对业务线程造成性能影响,后台写入也在独立线程中执行,不干扰UI或业务逻辑

内容的提问来源于stack exchange,提问作者Jeremy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:51:15