不要使用 Dispatcher.Invoke,因为它可能在你的延迟初始化 Lazy<T> 中导致死锁

栏目: ASP.NET · 发布时间: 5年前

内容简介:WPF 中为了 UI 的跨线程访问,提供了然而,如果你在 Lazy请先看一段非常简单的 WPF 代码:

WPF 中为了 UI 的跨线程访问,提供了 Dispatcher 线程模型。其 Invoke 方法,无论在哪个线程调用,都可以让传入的方法回到 UI 线程。

然而,如果你在 Lazy 上下文中使用了 `Invoke`,那么当这个 `Lazy ` 跨线程并发时,极有可能导致死锁。本文将具体说说这个例子。

一段死锁的代码

请先看一段非常简单的 WPF 代码:

private Lazy<Walterlv> _walterlvLazy = new Lazy<Walterlv>(() => new Walterlv());

private void OnLoaded(object sender, RoutedEventArgs e)
{
    Task.Run(() =>
    {
        // 在后台线程通过 Lazy 获取。
        var backgroundWalterlv = _walterlvLazy.Value;
    });

    // 等待一个时间,这样可以确保后台线程先访问到 Lazy,并且在完成之前,UI 线程也能访问到 Lazy。
    Thread.Sleep(50);

    // 在主线程通过 Lazy 获取。
    var walterlv = _walterlvLazy.Value;
}

而其中的 Walterlv 类的定义也是非常简单的:

class Walterlv
{
    public Walterlv()
    {
        // 等待一段时间,是为了给我么的测试程序一个准确的时机。
        Thread.Sleep(100);

        // Invoke 到主线程执行,里面什么都不做是为了证明绝不是里面代码带来的影响。
        Application.Current.Dispatcher.Invoke(() =>
        {
        });
    }
}

这里的 Application.Current.Dispatcher 并不一定必须是 Application.Current ,只要是两个不同线程拿到的 Dispatcher 的实例是同一个,就会死锁。

此死锁的触发条件

  1. Lazy<T> 的线程安全参数设置为默认的,也就是 LazyThreadSafetyMode.ExecutionAndPublication
  2. 后台线程和主 UI 线程并发访问这个 Lazy<T> ,且后台线程先于主 UI 线程访问这个 Lazy<T>
  3. Lazy<T> 内部的代码包含主线程的 Invoke

此死锁的原因

  1. 后台线程访问到 Lazy,于是 Lazy 内部获得同步锁;
  2. 主 UI 线程访问到 Lazy,于是主 UI 线程等待同步锁完成,并进入阻塞状态(以至于不能处理消息循环);
  3. 后台线程的初始化调用到 Invoke 需要到 UI 线程完成指定的任务后才会返回,但 UI 线程此时阻塞不能处理消息循环,以至于无法完成 Invoke 内的任务;

于是,后台线程在等待 UI 线程处理消息以便让 Invoke 完成,而主 UI 线程由于进入 Lazy 的等待,于是不能完成 Invoke 中的任务;于是发生死锁。

此死锁的解决方法

Invoke 改为 InvokeAsync 便能解锁。

这么做能解决的原因是:后台线程能够及时返回,这样 UI 线程便能够继续执行,包括执行 InvokeAsync 中传入的任务。

实际上,以上可能是最好的解决办法了。因为:

Invoke

所以,这段初始化代码既然不可避免地会并发,那么就应该阻止并发造成的死锁问题。也就是不要使用 Invoke 而是改用 InvokeAsync

如果需要使用 Invoke 的返回值,那么改为 InvokeAsync 之后,可以使用 await 异步等待返回值。

更多死锁问题

死锁问题:

解决方法:


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

构建之法(第二版)

构建之法(第二版)

邹欣 / 人民邮电出版社 / 2015-7 / 59

软件工程牵涉的范围很广, 同时也是一般院校的同学反映比较空洞乏味的课程。 但是软件工程的技术对于投身IT 产业的学生来说是非常重要的。作者邹欣有长达20年的一线软件开发经验,他利用业余时间在数所高校进行了长达6年的软件工程教学实践,总结出了在16周的时间内让同学们通过 “做中学 (Learning By Doing)” 掌握实用的软件工程技术的教学计划,并得到高校师生的积极反馈。在此基础上,作者对......一起来看看 《构建之法(第二版)》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具