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

如何在异步上下文正确实现SemaphoreSlim?附日志操作代码示例

用SemaphoreSlim异步保护日志操作的正确方式

你的这段日志代码在多线程/异步场景下存在两个线程安全问题:一是多个线程同时写入日志文件会导致文件占用异常、日志内容错乱;二是全局变量ALL_LOGS的拼接操作非原子性,多线程修改会出现内容覆盖。SemaphoreSlim原生支持异步上下文,能完美解决这些问题,具体实现如下:

1. 定义全局唯一的SemaphoreSlim实例

在日志类中定义静态的SemaphoreSlim对象,初始计数设为1(保证同一时间仅一个线程能进入临界区):

private static readonly SemaphoreSlim _logSemaphore = new SemaphoreSlim(1, 1);

2. 异步保护临界区操作

将文件写入、ALL_LOGS拼接等线程不安全的操作,放到信号量保护范围内,用WaitAsync()异步等待信号量,并用try/finally确保信号量必被释放(即使操作出错):

// 方法需标记为async Task/async ValueTask以支持await
public async Task WriteLogAsync(string log)
{
    await _logSemaphore.WaitAsync();
    try
    {
        if (!string.IsNullOrEmpty(LOGS_FILE) && File.Exists(LOGS_FILE))
        {
            // 用异步写入进一步适配异步场景性能
            using (StreamWriter streamWriter = new StreamWriter(LOGS_FILE, true))
            {
                await streamWriter.WriteLineAsync(log);
            }
        }

        // 全局变量拼接需放入临界区,避免多线程覆盖
        ALL_LOGS += log + Environment.NewLine;
    }
    finally
    {
        _logSemaphore.Release();
    }

    // Debug.WriteLine本身线程安全,无需放入临界区
    if (IsDebuggerAttached())
    {
        System.Diagnostics.Debug.WriteLine(log);
    }
}

关键注意事项

  • 必须保证SemaphoreSlim是全局唯一的(静态或单例实例),否则无法起到互斥作用
  • 务必使用WaitAsync()而非Wait(),前者适配异步上下文,不会阻塞线程池线程
  • 所有涉及共享资源的操作都要放在try块内,确保被信号量保护
  • finally块释放信号量是强制要求,否则会导致信号量被永久占用,后续线程无法进入临界区

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 06:32:37