2015-02-24 30 views
2

它是安全的UI线程的TaskScheduler存储在一个领域如下:将UI线程的TaskScheduler存储在字段中是否安全?

class TaskSchedulerReference { 

    private readonly _uiTaskScheduler; 

    // Constructor is called by the UI Thead 
    public TaskSchedulerReference() { 
     _uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext() 
    } 

    public TaskScheduler UiTaskScheduler { get { return _uiTaskScheduler; } } 
} 

...所以有可能在任何时间从任何后台线程通知UI在Task.ContinueWith(action, TaskSchedulerReference.UiTaskScheduler)回调。

是否保证在整个应用程序生命周期中引用仍然有效?

+2

这个静态初始化器非常危险。请参阅[我的答案](http://stackoverflow.com/questions/25751465/prism-5-delegatecommandbase-raisecanexecutechanged-throws-invalidoperationexcept/27406194#27406194)我在哪里解释如何可以这样的事情搞砸了整个应用程序。不保证该字段将在UI线程上初始化。 – dymanoid 2015-02-24 16:23:13

+0

请注意,这不是SC,它是使用SC的'TaskScheduler'。 – i3arnon 2015-02-24 16:59:22

+0

忘记静态初始值设定项。这不是重点。我纠正了这个问题...... – jeromerg 2015-02-24 17:07:18

回答

5

除了那个可疑的// This class is first visited by the UI Thread,是的。相反,使用一个显式的初始化器(显式地从UI线程运行),JIT不保证在UI线程上运行类初始化器。

但是,我更喜欢将上下文捕获为局部变量。在多线程(和异步编程)中将任何东西公开为全局状态都很棘手。总是尝试尽可能使用本地状态。它也反映了旧的IsInvokeRequired模式。每种方法都应该非常明确地说明发生了什么 - 这很容易导致无意中引入重入代码和死锁。

+0

谢谢。我的恐惧并不涉及静态领域(这个例子只是为了提供一个插图):问题是:可能对SynchronizationContext的引用变得无效?特别是,我害怕调用'SynchronizationContext.SetSynchronizationContext(context)',这将使存储的字段完全过时... – jeromerg 2015-02-24 17:05:18

+1

@jeromerg是啊,你不必担心,在Windows窗体应用程序 - 如果您拥有多个同步上下文,那么无论如何您都会遇到麻烦:D。但是,如果您发现自己编写Web应用程序,那么它将无法工作 - 这是传递上下文而不是将其放在全局字段中的另一个原因。 – Luaan 2015-02-25 08:28:42

0

如果你看看你code for FromCurrentSynchronizationContext可以看到,它通过捕获SynchronizationContext.Current创建SynchronizationContextTaskScheduler

只要你在UI线程上做到这一点,就可以捕获UI的SC,并且SynchronizationContext.SetSynchronizationContext(context)不能更改捕获的上下文。

请注意,你存储的是一个TaskScheduler持有SC而不是SC本身。如果你想捕捉SC只使用SynchronizationContext.Current

相关问题