zoukankan      html  css  js  c++  java
  • C#里的Thread.Join与Control.Invoke死锁情况

    Thread.Join会导致调用线程挂起, 等待Thread结束后继续执行.

    此时若调用线程为主线程(UI线程)同时Thread里面调用了控件的Invoke方法, 则有可能会导致死锁

    代码如下:

     1     public delegate void InvokeHandler();
     2     static class Extensions
     3     {
     4         public static void SafeInvoke(this Control control, InvokeHandler handler)
     5         {
     6             if (control.InvokeRequired)
     7             {
     8                 control.Invoke(handler);
     9             }
    10             else
    11             {
    12                 handler();
    13             }
    14         }
    15         public static void BeginSafeInvoke(this Control control, InvokeHandler handler)
    16         {
    17             if (control.InvokeRequired)
    18             {
    19                 control.BeginInvoke(handler);
    20             }
    21             else
    22             {
    23                 handler();
    24             }
    25         }
    26     }
     1     class UserInfo
     2     {
     3         public string Account;
     4         public string Password;
     5         public ListViewItem LVItem;
     6         public void SetListViewItemText(int subindex, string text)
     7         {
     8             LVItem.ListView.BeginSafeInvoke(() => //起初使用的是SafeInvoke, 会导致死锁
     9             {
    10                 LVItem.SubItems[subindex].Text = text;
    11                 LVItem.ListView.Refresh();
    12             });
    13             
    14         }
    15     }
     1         public void Stop()
     2         {
     3             _event.Set(); //通知线程要退出
     4             _thread.Join(); //A. 等待线程处理完(此处和B导致死锁)
     5             _thread = null;
     6             _event.Close();
     7             _event = null;
     8         }
     9         private void Run()
    10         {
    11             _user.SetListViewItemText(1, "正在登录...");
    12             _loginTime = DateTime.Now;
    13             while (_event.WaitOne(5000) == false)
    14             {
    15                 TimeSpan span = DateTime.Now - _loginTime;
    16 
    17                 _user.SetListViewItemText(1, string.Format("已登录: {0}", span.ToString()));
    18             }
    19             _user.SetListViewItemText(1, "已停止"); //B. Invoke方式来更新控件内容(此处和A导致死锁)
    20         }

     通过代码可以看出, 起初更新相关控件内容时采用的Invoke方式, Invoke会使调用线程挂起并在UI线程上执行相关方法, 直到执行完毕后, 调用线程才会继续.

    也就是说Invoke会等待UI操作完成才继续. 而上面代码里由于在UI线程上调用了Stop, 在A处UI线程会处于挂起状态, 这时Run方法所处的线程要更新UI, 调用了Invoke, 这时因为UI线程处于挂起状态, Invoke得不到执行, 所以Run方法所在的线程也挂起了, 永远不会结束. 这样A处就一直挂在那了, 两个都挂着, 就行成死锁了.

    解决方案也很简单: 就是把Invoke换成BeginInvoke, BeginInvoke是异步方式执行, 也就是说调用线程执行BeginInvoke不会挂起, 这样就不会导致死锁了.

  • 相关阅读:
    Android标题栏最右边添加按钮
    Activity标题栏添加返回按钮
    【Android】解决Android横竖屏切换数据丢失问题的方法
    Android热更新,到底是更新啥?
    vm ware 虚拟WIN10 时,chrome ,cent browser 显示异常,花屏
    动态生成的 select option 无法选中,设置值
    安装sql 2012 时遇到“需要更新的以前的 Visual Studio 2010 实例。”规则失败。
    C#.NET 简单使用log4net
    10位,13位时间戳转为C#格式时间
    C# .NET Unix 时间戳
  • 原文地址:https://www.cnblogs.com/Athrob/p/4137637.html
Copyright © 2011-2022 走看看