比较的SynchronizationContext(Comparing Synchronizatio

2019-08-03 01:41发布

如何比较的SynchronizationContext? 看来,同样的调度员可以使用的BeginInvoke时创建不同的SynchronizationContext。 当我深入到两个(不等)环境中,我看到,调度线程ID是一样的,但它们不是彼此相等。

public partial class MainWindow : Window
{
    private SynchronizationContext contexta;
    private SynchronizationContext contextb;
    private SynchronizationContext contextc;
    private SynchronizationContext contextd;

    public MainWindow()
    {
        InitializeComponent();

        contexta = SynchronizationContext.Current;

        Loaded += MainWindow_Loaded;
    }

    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        contextb = SynchronizationContext.Current;

        Dispatcher.Invoke(() =>
            {
                contextc = SynchronizationContext.Current;
            });

        Dispatcher.BeginInvoke(new Action(() =>
            {
                contextd = SynchronizationContext.Current;
            }));

        Debug.Assert(contexta != contextb);
        Debug.Assert(contexta == contextc);         // fails... why?!?!?
        Debug.Assert(contexta == contextd);         // fails... why?!?!?
        Debug.Assert(contextc == contextd);         // fails... why?!?!?
    }        

也许他们两个人不能一起使用。 我注意到,这实际工作:

        contexta.Send(new SendOrPostCallback((s) =>
            {
                contexte = SynchronizationContext.Current;
            }), null);

更新 ,但奇怪的是,它并不总是工作。

    public override void AddRange(IEnumerable<T> items)
    {
        if (SynchronizationContext.Current == _context)
        {
            base.AddRange(items);
        }
        else
        {
            _context.Send(new SendOrPostCallback((state) =>
                {
                    AddRange(state as IEnumerable<T>);
                }), items);
        }
    }

从来没有得到匹配_context和永远的推移,例如。 尽管它不应该。 这后一种实施例的螺纹实际上最终是相同的,并有一个上下文,但它是不同的。

UPDATE2好吧,我得到它的工作,但我真的感到不舒服了。 显然,当你发布或发送,你的任务是从右边线运行,但如果你不是从UI的到来,似乎产生了新的SynchronizationContext。

    public override void AddRange(IEnumerable<T> items)
    {
        if (SynchronizationContext.Current == _context)
        {                       
            base.AddRange(items);
        }
        else
        {
            _context.Post(new SendOrPostCallback((state) =>
                {
                    if (SynchronizationContext.Current != _context)
                        SynchronizationContext.SetSynchronizationContext(_context);     // called every time.. strange
                    AddRange(items);
                }), null);
        }
    }

看看这个:

“需要对直接调用方完全信任。此成员不能由部分受信任的或透明的代码中使用。” :(

Answer 1:

我觉得你有兴趣BaseCompatibilityPreferences.ReuseDispatcherSynchronizationContextInstance 。

此设置规定的单一的SynchronizationContext实例是否被用于一个给定的调度器对象与否。 它默认为true,直到.NET 4中,并在.NET 4.5假(这是行为的改变是LukeN观察)。

现在,如果你的目标只是为了让直接调用,而不是调用。发送()我会说:

  1. 调用。发送()时,该DispatcherSynchronizationContext实际上只是使一个直接调用,如果你是在正确的线程(不使用调度队列),这样你就不会获得太多反正从额外层(几张支票,并呼吁间接)。

  2. 如果你只对WPF的代码,你可以使用Dispatcher.CheckAccess()和Dispatcher.Invoke()做你想要什么。

在一般情况下,没有办法“比较”两个SynchronizationContexts,所以你只要调用。发送()。 这不可能是一个性能问题,无论如何,请记住,过早的优化是一切罪恶的根源 - >测量第一。



文章来源: Comparing SynchronizationContext