Winform多线程处理

        本人没做过基于WPF的应用程序,对数据驱动不太了解,没具体做过,经常做的一些是基于Winform的应用程序,在很多即时操作场景当中,对于多线程操作,大多数都一知半解,我也一样,但通过这些年的总结学习和使用,总结出一套使用多线程与窗体异步交互的操作。

        多线程有多种操作方式,如Winform自带的BackgroundWorker控件,但对于真正开发时,本人使用的时候是非常少的,原因在于使用起来麻烦不说,还容易出错。再一个就是使用Thread函数,来自定义线程操作,我们可以将窗体看成是一个整体,线程代表各自执行的任务,每个任务执行完成后,告诉窗体如何显示,在Winform中,我喜欢在线程当中,使用事件触发的方式,来将信息反馈给窗体,这样既可以保证代码的整体逻辑晰,阅读性高,还可使线程中的各部分分工明确,即使一部分出问题,不影响整体。

        那么来说一说多线程的交互方式,在framework2.0以后,使用多线程时,要么使用CheckForIllegalCrossThreadCalls忽略线程错误,这样可以将数据直接反馈给窗体,缺点就是,当数据交互比较频繁时,容易出现数据冲突或内存错误,导致窗体显示部分的崩溃。第二,是使用delegate来交替实现,缺点是容易出现混乱,并且对于各部分操作来讲,每操作一个控件,写一堆委托,太麻烦。framework 3.0以后,出现了一个action,这个是一个简易的委托,可以减少委托的使用,太不可避免有访问不到窗体线程的时候,这时候需要一个控件的RequiadInvoke来判断,或者直接不判断,使用this.Invoke来直接异步,简单粗爆,但不可避免的还是会出现是否需要异步的操作,使程序崩溃,最后一个是使用AsyncOperation来实现,这个是异步操作管理器,我现在基本上是使用这个加Thread来实现整个窗体界面的线程与窗体之间的异步交互。以前上是我所使用过的所有线程操作方式,对比来讲,最后一个是最好的,前面的如果在操作频繁的程序当中,容易产生大量的Handle句柄,当超出65535个的时候,程序必然会崩溃,原因就是在程序执行线程过程当中,系统每生成一次线程,就会产生一个Handle,但当我们使用完成后,系统不会立即收回,而是在一定时间之后,才会收回。而AsyncOperation是可以告诉系统,所有线程使用的异步操作,立即可以收回。

        那么,如何使用AsyncOperation呢?当然,网上百度搜索一下,可以找出一堆的用法,但结合整体的程序,而不出问题的,基本没有,怎么使用,需要我们自己具体问题具体分析,而我在使用时,结合总结,使AsyncOperation可以基本上满足各种需求,举个例子:

public partial class Form1 : Form

{

        public Form1()

        {

                InitializeComponent();

        }

        private void button1_click(object sender, EventArgs e)

        {

                 Label1.text = string.Empty;

                for(int i = 0;i<1000;i++)

                {

                        Label1.text += i.ToString() + "\r\n";

                }

        }

}

这是一个简单的窗体程序,窗体上有控件Button和控件Label,Label负责显示信息,Button单击时,执行0~1000行的信息显示。不使用线程,程序执行时,感觉像是卡死了。那么来改一下:

public partial class Form1 : Form

{

        public Form1()

        {

                InitializeComponent();

        }

        private void button1_click(object sender, EventArgs e)

        {

                Thread thread = new Thread(new ThreadStart(Start));

                thread.Start();

        }

        private void Start()

        {

                Label1.text = string.Empty;

                for(int i = 0;i<1000;i++)

                {

                        this.Invoke(new Action(()=>{

                                Label1.text += i.ToString() + "\r\n";

                        }));

                }

        }

}

这时候程序运行的时候,打开任务管理器,会发现窗体句柄一直在涨,很难下去,那么我们再来改一下:

public partial class Form1 : Form

{

        AsyncOperation _AsyncOperation;

        public Form1()

        {

                InitializeComponent();

                _AsyncOperation = AsyncOperationManager.CreateOperation(null);

        }

        private void button1_click(object sender, EventArgs e)

        {

                Thread thread = new Thread(new ThreadStart(Start));

                thread.Start();

        }

        private void Start()

        {

                Label1.text = string.Empty;

                for(int i = 0;i<1000;i++)

                {

                        _AsyncOperation.Post(new                         System.Threading.SendOrPostCallback(delegate(object state) { 
                                Label1.text += i.ToString() + "\r\n";
                    }), null);

                        _AsyncOperation.OperationCompleted();

                }

        }

}

运行后,发现_AsyncOperation还是报错,原因是第二次调用时,_AsyncOperation已经被释放掉了,不能再被用了,最终修改方式就是:

public partial class Form1 : Form

{

        AsyncOperation _AsyncOperation;

        public Form1()

        {

                InitializeComponent();

        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);

                if(this.Visible)

                {

                         _AsyncOperation = AsyncOperationManager.CreateOperation(null);

                }

                else

                {

                        _AsyncOperation.OperationCompleted();

                }
        }

        private void button1_click(object sender, EventArgs e)

        {

                Thread thread = new Thread(new ThreadStart(Start));

                thread.Start();

        }

        private void Start()

        {

                Label1.text = string.Empty;

                for(int i = 0;i<1000;i++)

                {

                        _AsyncOperation.Post(new                         System.Threading.SendOrPostCallback(delegate(object state) { 
                                Label1.text += i.ToString() + "\r\n";
                    }), null);

                }

        }

}

对事件委托也一样,对于继续类父窗体,我喜欢使用protected virtual void Onxxx(EventArgs e)这样的写法,原因就是可以在很多情况下,子窗体可以使用override来重写。对于一般的窗体发生的事件,去掉virtual就好,可以把_AsyncOperation调用直接放在这里,这样,不管是窗体调用还是线程调用,只要写共用的方法调用就好,这样,就可以保证窗体间的异步调用不会出问题,并且在任务管理器当中,句柄的增长数非常低,并且释放的也及时,不用担心因柄句而导致程序崩溃。由于写得匆忙,只是记录一下,如有看见的,不要挑毛病,有不懂的可以提问,写的方试问题就不要讨论了。

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值