代码之家  ›  专栏  ›  技术社区  ›  asdf_enel_hak

从UI调用到系统时,锁挂起。穿线。线

  •  3
  • asdf_enel_hak  · 技术社区  · 8 年前

    编辑: 请参阅问题历史记录,了解未更改的问题,以免使评论无效。

    public partial class ucLoader : UserControl
    {
        //lock object for whole instance of class ucLoader
        private object lockUcLoader = new object();
    
        //bringing info from ui
        private void btnBringInfo_Click(object sender, EventArgs e)
        {
            lock (lockUcLoader)
            {
                btnBringInfo_PerformClick(false);
            }
        }
    
        //using this method because it could be called when even button not visible
        internal void btnBringInfo_PerformClick(bool calledFromBandInit)
        {
            lock (lockUcLoader) //HANGS HERE when called multiple times and ui freeze as well
            //by the way I am using (repetitive) lock, because this method also called independently from btnBringInfo_Click
            {
                //...
                this.btnLoad_PerformClick();
            }
        }
    
        //Another button perform click that could be triggered elsewhere when even button not visible
        private void btnLoad_PerformClick()
        {
            lock (lockUcLoader) //I am using (repetitive) lock, because this method also called independently from btnBringInfo_PerformClick
            {
                //...
                Run();  
            }
        }
    
        //method for creating thread which System.Threading.Thread  
        private void Run()
        {
           lock (lockUcLoader)  //Maybe this lock is NOT REQUIRED, as it is called by only btnLoad_PerformClick(), could you please confirm?
            {
                //some code that thread can be killed when available,  you can ingore this two lines as they are irrelevant to subject, I think
                Source = new CancellationTokenSource();
                Token = Source.Token;
                var shell = new WindowsShell();
                Thread = new Thread((object o) =>
                {
                    //...
                    var tokenInThread = (CancellationToken)o;
                    exitCode =TaskExtractBatchFiles(cls, shell, exitCode);
    
    
                     using (var logEnt = new logEntities())
                    {
    
                            //Do some db operation
                            //...
                            this.Invoke((MethodInvoker)delegate
                            {
                                //do some ui update operation
                                //...
                            });
                        }
                }
                Thread.Start(Token);
            }      
        } 
    
        public void Progress(string message)
        {
            Invoke((MethodInvoker)delegate  //ATTENTION HERE see below picture Wait occurs here
            {
                if (message != null && message.Trim() != string.Empty)
                {
                    this.txtStatus.AppendText(message + Environment.NewLine);
                }
            });
        }       
    }       
    

    为了避免陷入封闭式问题,我的问题是我该如何预防

    public void Progress(string message)
            {
                Invoke((MethodInvoker)delegate  //ATTENTION HERE see below picture Wait occurs here
                {
                    if (message != null && message.Trim() != string.Empty)
                    {
                        this.txtStatus.AppendText(message + Environment.NewLine);
                    }
                });
            }   
    

    enter image description here

    enter image description here

    1 回复  |  直到 8 年前
        1
  •  4
  •   Hans Passant    8 年前
       Invoke((MethodInvoker)delegate ...
    

    无论何时使用 lock 僵局

    你可以推理出来,锁在里面控制着。调用是确保工作线程被阻塞直到UI线程执行委托目标所必需的。可能也有助于解释程序陷入僵局的原因。你启动了worker线程,它获得了 lockUcLoader

    控制从调用日期。NET 1.0,该框架的一个版本,在与线程相关的代码中有几个严重的设计错误。虽然他们本想有所帮助,但他们只是为程序员设置了死亡陷阱。控制的独特之处是什么。调用就是这样

    区分控制。调用和控制。开始沉思。你只有一次 需要 防止

    因此,使用BeginInvoke已经足以解决这个问题。但这不是你应该停下来的地方。点击事件处理程序中的这些锁没有意义,它们所做的只是使用户界面没有响应,极大地困惑了用户。相反,您必须将这些按钮的Enable属性设置为 当工人完成时。现在它再也不会出错了,你不需要锁,用户得到了良好的反馈。

    this Q+A .

    推荐文章