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

我的C#代码是否存在时序/竞态条件问题?

自定义IProgress实现TimerProgress的测试时序问题分析

核心结论

你的问题本质是异步回调的调度时序问题,和处理器变量更新方式无关。

问题拆解

  1. 为什么测试代码极少时失败,加注释就正常?
    IProgress<T>(包括基于它的自定义实现)的Report方法默认会将回调委托调度到当前的同步上下文执行。在测试环境(如xUnit/NUnit)中,同步上下文通常是null,此时回调会被抛到线程池异步执行。

    • 当测试代码极精简时,测试主线程的执行速度远快于线程池回调的调度速度,主线程还没等回调完成更新reportValue,就直接进入断言环节,自然会拿到初始值0。
    • 加注释后,测试主线程的执行流程出现了微小的间隙(哪怕注释本身不执行任何逻辑,编译后的代码执行节奏也会有细微变化),给线程池回调留出了足够的执行时间,reportValue被正确更新,断言通过。
  2. 为什么排除处理器变量更新的问题?
    如果是处理器缓存导致变量更新不可见,问题表现会是随机失败,而非"测试代码少就必败、加注释就必过"的确定性现象。只要reportValue不是被编译器优化为常量,就不会出现这类更新可见性问题(当然,若要严谨,可给reportValue加上volatile修饰,但这不是你当前问题的核心)。

可行的解决办法

1. 显式同步等待回调完成(推荐)

在测试代码中使用TaskCompletionSource或ManualResetEventSlim来等待回调执行到预期状态,避免依赖不可靠的"自然延迟":

// 用TaskCompletionSource等待回调触发到目标值
var tcs = new TaskCompletionSource<bool>();
int reportValue = 0;

var progress = new TimerProgress<int>(value => {
    reportValue = value;
    if (value == 5) // 当达到预期值时标记完成
        tcs.SetResult(true);
});

// 启动TimerProgress的计数逻辑
progress.Start();

// 等待回调完成,设置超时防止死锁
await tcs.Task.WaitAsync(TimeSpan.FromSeconds(6));

// 此时再执行断言
Assert.Equal(5, reportValue);

2. 测试场景下强制同步执行回调

若仅为测试需求,可修改自定义TimerProgress的实现,允许在构造时跳过同步上下文调度,直接同步执行回调:

public class TimerProgress<T> : IProgress<T>
{
    private readonly Action<T> _handler;
    private readonly bool _executeSynchronously;

    public TimerProgress(Action<T> handler, bool executeSynchronously = false)
    {
        _handler = handler;
        _executeSynchronously = executeSynchronously;
    }

    public void Report(T value)
    {
        if (_executeSynchronously)
        {
            _handler(value); // 同步执行,测试时用
        }
        else
        {
            // 原有的异步上下文调度逻辑
            var syncContext = SynchronizationContext.Current ?? TaskScheduler.Current;
            syncContext.Post(_ => _handler(value), null);
        }
    }

    // 其他Timer相关逻辑...
}

测试时传入executeSynchronously: true,即可让回调同步执行,断言无需等待。


内容的提问来源于stack exchange,提问作者Pure.Krome

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 07:12:45