IProgress <t>未触发</t>

时间:2014-11-10 19:34:43

标签: c# .net .net-4.5

我有以下剪辑代码:

var progress = new Progress<string>();
var count = 0;
progress.ProgressChanged += (o, transferProgress) => ++count;
for (var i = 0; i < 10; i++)
{
    ((IProgress<string>)progress).Report(i.ToString(CultureInfo.InvariantCulture));
}
Console.WriteLine(count);

在这种情况下,count变量永远不会增加。那是为什么?

更新 事件似乎正在解雇,但它们只是“迟到”(正如一些人在下面指出的那样)。为了提供更多上下文,这段代码被放置在按钮单击事件处理程序中的Win Forms应用程序中。无论我在处理程序中做了什么(即休眠了x秒),直到按钮点击处理程序没有完成执行,事件才会触发。我怎样才能绕过这个以获得“及时”的活动?

1 个答案:

答案 0 :(得分:4)

来自Progress<T> documentation

  

提供给使用ProgressChanged事件注册的构造函数或事件处理程序的任何处理程序都是通过构造实例时捕获的SynchronizationContext实例调用的。如果在构造时没有当前的SynchronizationContext,则将在ThreadPool上调用回调。

这里可能发生的事情是你确实有一个同步上下文,所以回调被延迟到一段时间后,这取决于管理这段代码执行的特定同步上下文的行为。

请注意,即使您没有在同步上下文中运行,也不能保证count == 10跟在循环体之后,因为线程池可能尚未执行所有回调。

此外,由于变量未声明volatile,因此当前线程可能无法观察到另一个线程所做的更改,因为允许运行时/ JIT缓存在单线程上下文中无法更改的值。为了安全起见,您还希望在回调中使用Interlocked.Increment(ref count),以防两个回调同时执行,因为++count不是原子操作。 (这仅在通过线程池调度回调时才相关。)

tl; dr版本是“欢迎并发。”