C#多线程避免用户界面死锁

在编写winform应用程序时,当主线程中要处理耗时任务时,往往会导致用户界面(以下称为UI)的假死,即UI不响应用户的鼠标,键盘等操作.

耗时任务有很多种,比如:

  • 向远程服务器发送和请求数据(http,smtp等);
  • 大量的运算(信号处理,大量数据处理等);
  • 其他(暂时只遇过以上两种情况)

以前最常使用编程环境是LabVIEW,在LabVIEW中只要架构合理就可以避免UI假死情况的发生,我常用的架构是生产者-消费者循环(具体内容可参考NI Community).在这种架构中,事件的接收和处理是放在两个不同的线程中进行的,线程之间使用线程安全的队列进行通信,所以耗时任务的处理并不会影响UI的响应,只是任务处理结果的输出会有延时.

在C#中,也可以使用这种思想来避免UI假死,不过实现起来相对LabVIEW要复杂不少,

首先是要用户自己管理线程,

第二是在C#新版本中,界面控件只可以由创建它的线程对其进行修改,也就是说在主线程中创建的控件,只能由主线程进行修改,如果在其他线程中使用诸如 textBox.Text = "xxx";这样的语句是没有效果,并且会导致异常.这种问题需要使用delegate函数委托,在其他线程中使用this.Invoke()通过委托调用主线程函数对控件进行修改.

具体的部分代码如下:
首先需要using System.Threading;来使用线程

 


namespace UIMultiThreadsTest1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
           
            
        }

        //声明线程
        public Thread myUpdateUIThread;

        //定义委托,用于更新界面显示
        public delegate void DeleUpdateUIText(string msg);
       
       

        public void ThreadUpdateUIText(int n)
        {
            string sep = Environment.NewLine;

            this.Invoke((ParameterizedThreadStart)delegate (object msg)
            {
                string msg1 = (string) msg;
                textBox1.AppendText(msg1);
              
            }, (object)"线程开始"+sep);
            for(int index=0;index<n; index++)
            {
                this.Invoke((DeleUpdateUIText)delegate(string msg)
                {
                    textBox1.AppendText(msg);
                }, "进行到" + index + sep);

                Thread.Sleep(300);
            }
            this.Invoke((DeleUpdateUIText) delegate(string msg)
            {
                textBox1.AppendText(msg);
            }, "线程结束"+sep);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            myUpdateUIThread = new Thread(new ThreadStart(
                delegate { ThreadUpdateUIText(10); }));
            myUpdateUIThread.Start();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            //退出窗体前关闭线程,避免窗体退出,面板控件引用皆释放,
            //UpdateUIText引发异常
            myUpdateUIThread.Abort();
        }
    }
}
 

以上注释基本比较详细了

 

工程文件下载:

UIMultiThreadsTest


原创文章,转载请注明: 转载自张哲的博客

本文链接地址: C#多线程避免用户界面死锁