.NET Core中BackgroundService缓存报错:SemaphoreFullException异常
问题分析与修复
异常根源
你遇到的SemaphoreFullException是因为信号量的释放次数超过了获取次数:
CacheSignal<T>中的SemaphoreSlim初始计数为1,最大计数也为1。CacheWorker.StartAsync中提前调用了_cacheSignal.WaitAsync(),将信号量计数从1减为0。- 第一次
ExecuteAsync循环结束时,finally块中的Release()将计数恢复为1。 - 第二次循环时,代码没有重新获取信号量(未调用
WaitAsync()),直接执行Release(),尝试将计数从1加至2,超过了最大计数1,触发异常。
修复方案
步骤1:移除StartAsync中多余的信号量获取
删除CacheWorker.StartAsync里的await _cacheSignal.WaitAsync();,该操作会提前占用信号量且无对应释放逻辑,破坏了"获取-释放"的配对关系。
修改后的StartAsync:
public override async Task StartAsync(CancellationToken cancellationToken) { await base.StartAsync(cancellationToken); }
步骤2:在ExecuteAsync循环中正确配对信号量操作
每次缓存更新前先获取信号量,确保"获取-释放"严格配对,避免重复释放。修改ExecuteAsync:
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { await _cacheSignal.WaitAsync(stoppingToken); try { WeatherForecast[]? forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); _cache.Set("FORECASTS", forecasts); } finally { _cacheSignal.Release(); } try { await Task.Delay(TimeSpan.FromMinutes(2), stoppingToken); } catch (OperationCanceledException) { break; } } }
额外说明
WeatherService中的信号量使用逻辑是正确的:每次请求获取信号量,确保缓存更新时请求等待,避免读取未完成的缓存数据,无需修改。
内容的提问来源于stack exchange,提问作者Reinder Wit
相关产品推荐
相关产品推荐

