.NET 多线程

Net66编写

一、引言
     在编写Windows form时,如果直接在UI线程要运行一个费时方法的话(如从数据库查询大量数据时),会引起程序“假死”,从而导致用户不满。这个时候就需要通过多线程技术来解决,提高界面交互性能,方便用户使用。
一般通过三种方式解决:
1.通过System.Threading.Thread类,创建新的线程,Thread.Start运行费时方法。
2.通过System.Threading.ThreadPool类,将费时任务提交到线程池中,等待运行。
以上两种方法,基本思路是在UI界面中控制线程的启动和中止,在线程中回调用UI界面方法,更新界面。在线程中回调UI界面方法时,特别是涉及更新控件属性时,如果不注意,存在很大的隐患。这两种办法,编码和控制结构较为复杂,需要启动和管理额外的线程占用资源。
3.通过异步委托调用,将该方法排队到系统线程池的线程中运行,而在费时方法中也通过Control.BeginInvoke异步回调,达到"启动后不管"的目的。
这种方法,编码简单,程序结构较为清晰,充分利用.NET框架的异步委托功能,但要对异步调用知识较熟悉。
相关知识点参见
     现利用.NET异步委托调用功能,编写Task抽象类,以方便管理后台工作线程,衔接后台线程与UI线程的联系。该抽象类提供了调用和管理的框架,没有方法的实现细节,通过继承类、重写方法,可以实现想要的功能。主要功能如下:
1.利用异步委托调用,实际多线程,不需要单独后台线程。
2.通过委托、事件驱动,实际后台与前台UI线程的联系,实现事件广播。
3.支持正常取消后台工作方法(费时方法)运行,也可以强制中止线程。
4.能够捕获取消、强制中止和方法出错三种情况,并突发相关事件,以便进行释放资源等操作。
5.通过异步调用,在工作方法中安全调用涉及UI控件的方法。
6.自行管理工作进程状态,提供状态变化事件。
7.只要工作方法调用签名,符合定义的TaskDelegate委托接口,可通过StartTask(TaskDelegate worker ,params object[] args )方便调用。在实际使用时,可在继承类中定义多个相同调用接口的方法,避免重复编码,较为方便。

给大家作个参考,而大牛呢,多点指正。当是扔个砖头,想砸块玉吧。


二、代码


  1using System;
  2using System.Windows.Forms;
  3
  4namespace Net66.AsynchThread
  5{
  6    /** <summary>
  7    /// 任务工作状态
  8    /// </summary>
  9    public enum TaskStatus 
 10    { 
 11        /** <summary>
 12        /// 任务没有运行,可能是工作进程没有开始、工作进程正常结束或正常取消工作进程
 13        /// </summary>
 14        Stopped, 
 15        /** <summary>
 16        /// 任务没有运行,被调用者强行中止
 17        /// </summary>
 18        Aborted,
 19        /** <summary>
 20        /// 任务没有运行,在工作进程中触发错误而中止
 21        /// </summary>
 22        ThrowErrorStoped,
 23        /** <summary>
 24        /// 任务运行中
 25        /// </summary>
 26        Running, 
 27        /** <summary>
 28        /// 尝试取消工作进程中
 29        /// </summary>
 30        CancelPending,
 31        /** <summary>
 32        /// 强行中止工作进程中
 33        /// </summary>
 34        AbortPending
 35
 36    } 
 37
 38    /** <summary>
 39    /// 任务状态消息
 40    /// </summary>
 41    public class TaskEventArgs : EventArgs 
 42    { 
 43        /** <summary>
 44        /// 任务运行结果
 45        /// </summary>
 46        public Object     Result; 
 47        /** <summary>
 48        /// 任务进度(0-100)
 49        /// </summary>
 50        public int        Progress; 
 51        /** <summary>
 52        /// 任务工作状态
 53        /// </summary>
 54        public TaskStatus Status; 
 55        /** <summary>
 56        /// 任务消息文本
 57        /// </summary>
 58        public String Message;
 59        /** <summary>
 60        /// 创建任务状态消息
 61        /// </summary>
 62        /// <param name="progress">任务进度(0-100)</param>
 63        public TaskEventArgs( int progress ) 
 64        { 
 65            this.Progress = progress; 
 66            this.Status   = TaskStatus.Running; 
 67        } 
 68        /** <summary>
 69        /// 创建任务状态消息
 70        /// </summary>
 71        /// <param name="status">任务线程状态</param>
 72        public TaskEventArgs( TaskStatus status ) 
 73        { 
 74            this.Status = status; 
 75        } 
 76        /** <summary>
 77        /// 创建任务状态消息
 78        /// </summary>
 79        /// <param name="progress">任务进度(0-100)</param>
 80        /// <param name="result">任务运行中间结果</param>
 81        public TaskEventArgs( int progress,object result ) 
 82        { 
 83            this.Progress = progress; 
 84            this.Status   = TaskStatus.Running; 
 85            this.Result   = result;
 86        } 
 87        /** <summary>
 88        /// 创建任务状态消息
 89        /// </summary>
 90        /// <param name="status">任务线程状态</param>
 91        /// <param name="result">任务运行结果</param>
 92        public TaskEventArgs( TaskStatus status,object result ) 
 93        { 
 94            this.Status   = status; 
 95            this.Result   = result;
 96        } 
 97        /** <summary>
 98        /// 创建任务状态消息
 99        /// </summary>
100        /// <param name="status">任务线程状态</param>
101        /// <param name="message">消息文本</param>
102        /// <param name="result">任务运行结果</param>
103        public TaskEventArgs( TaskStatus status,string message ,object result ) 
104        { 
105            this.Status   = status; 
106            this.Message = message;
107            this.Result   = result;
108        } 
109        /** <summary>
110        /// 创建任务状态消息
111        /// </summary>
112        /// <param name="progress">任务进度(0-100)</param>
113        /// <param name="message">消息文本</param>
114        /// <param name="result">任务运行中间结果</param>
115        public TaskEventArgs( int progress,string message ,object result ) 
116        { 
117            this.Progress = progress; 
118            this.Status   = TaskStatus.Running; 
119            this.Message = message;
120            this.Result   = result;
121        } 
122        /** <summary>
123        /// 创建任务状态消息
124        /// </summary>
125        /// <param name="status">任务线程状态</param>
126        /// <param name="progress">任务进度(0-100)</param>
127        /// <param name="message">消息文本</param>
128        /// <param name="result">任务运行中间结果</param>
129        public TaskEventArgs( TaskStatus status,int progress,string message ,object result ) 
130        { 
131            this.Status = status;
132            this.Progress = progress; 
133            this.Message = message;
134            this.Result   = result;
135        } 
136    }     
137
138    /** <summary>
139    /// 任务的工作方法(Work)的委托接口
140    /// 传入值:对象数组(object[])
141    /// 返回值:对象(object)
142    /// </summary>
143    public delegate object TaskDelegate( params object[] args ); 
144
145    /** <summary>
146    /// 任务事件的委托接口
147    /// </summary>
148    public delegate void TaskEventHandler( object sender, TaskEventArgs e ); 
149
150    abstract public class Task
151    {   
152        内部属性#region 内部属性
153        /** <summary>
154        /// 任务调用线程(前台或UI线程)
155        /// </summary>
156        protected System.Threading.Thread _callThread = null; 
157        /** <summary>
158        /// 任务工作线程(后台)
159        /// </summary>
160        protected System.Threading.Thread _workThread = null; 
161        /** <summary>
162        /// 任务工作状态
163        /// </summary>
164        protected TaskStatus _taskState = TaskStatus.Stopped; 
165        /** <summary>
166        /// 任务进度(0-100)
167        /// </summary>
168        protected int _progress = -1;
169        /** <summary>
170        /// 任务工作结果
171        /// </summary>
172        protected object _result = null;
173        /** <summary>
174        /// 任务工作进程出错时,捕获的异常对象
175        /// </summary>
176        protected Exception _exception = null;
177        #endregion
178
179        事件#region 事件
180        /** <summary>
181        /// 任务工作状态变化事件
182        /// </summary>
183        public event TaskEventHandler TaskStatusChanged; 
184        /** <summary>
185        /// 任务进度变化事件
186        /// </summary>
187        public event TaskEventHandler TaskProgressChanged; 
188        /** <summary>
189        /// 任务被调用者强行中止事件
190        /// </summary>
191        public event TaskEventHandler TaskAbort; 
192        /** <summary>
193        /// 任务工作方法执行中触发错误事件
194        /// </summary>
195        public event TaskEventHandler TaskThrowError; 
196        /** <summary>
197        /// 任务被调用者取消事件
198        /// </summary>
199        public event TaskEventHandler TaskCancel; 
200        #endregion
201
202        属性#region 属性
203        
204        /** <summary>
205        /// 任务工作进程出错时,捕获的异常对象
206        /// </summary>
207        public Exception Exception
208        {
209            get { return _exception;}
210        }
211        /** <summary>
212        /// 任务调用线程(前台或UI线程)
213        /// </summary>
214        public System.Threading.Thread CallThread
215        {
216            get { return _callThread;}
217        }
218        /** <summary>
219        /// 任务工作线程(后台)
220        /// </summary>
221        public System.Threading.Thread WordThread
222        {
223            get {return _workThread;}
224        }
225        
226        /** <summary>
227        /// 任务进度(0-100)
228        /// </summary>
229        public int Progress
230        {
231            get {return _progress;} 
232        }
233        /** <summary>
234        /// 任务工作状态
235        /// </summary>
236        public TaskStatus TaskState
237        {
238            get {return _taskState;}
239        }
240        /** <summary>
241        /// 任务工作结果
242        /// </summary>
243        public object Result
244        {
245            get {return _result;}
246        }
247
248        protected bool IsStop
249        {
250            get
251            {
252                bool result = false;
253                switch (_taskState)
254                {
255                    case TaskStatus.Stopped:
256                    case TaskStatus.Aborted:
257                    case TaskStatus.ThrowErrorStoped:
258                        result = true;
259                        break;
260                    default:
261                        break;
262                }
263                return result;
264            }
265        }
266        #endregion
267
268        触发事件#region 触发事件
269        /** <summary>
270        /// 触发任务工作状态变化事件
271        /// </summary>
272        /// <param name="status">任务工作状态</param>
273        /// <param name="result">任务工作结果对象</param>
274        protected void FireStatusChangedEvent(TaskStatus status, object result) 
275        { 
276            if( TaskStatusChanged != null ) 
277            { 
278                TaskEventArgs args = new TaskEventArgs( status,result); 
279                AsyncInvoke(TaskStatusChanged,args);
280            } 
281        } 
282 
283        /** <summary>
284        /// 触发任务进度变化事件
285        /// </summary>
286        /// <param name="progress">任务进度(0-100)</param>
287        /// <param name="result">任务工作中间结果对象</param>
288        protected void FireProgressChangedEvent(int progress, object result) 
289        { 
290            if( TaskProgressChanged != null ) 
291            { 
292                TaskEventArgs args = new TaskEventArgs( progress,result); 
293                AsyncInvoke(TaskProgressChanged,args);
294            } 
295        } 
296        /** <summary>
297        /// 触发工作方法执行中发现错误事件
298        /// </summary>
299        /// <param name="progress">任务进度(0-100)</param>
300        /// <param name="result">任务工作中间结果对象</param>
301        protected void FireThrowErrorEvent(int progress, object result) 
302        { 
303            if( TaskThrowError != null ) 
304            { 
305                TaskEventArgs args = new TaskEventArgs( progress,result); 
306                AsyncInvoke(TaskThrowError,args);
307            } 
308        } 
309        /** <summary>
310        /// 触发被调用者取消事件
311        /// </summary>
312        /// <param name="progress">任务进度(0-100)</param>
313        /// <param name="result">任务工作中间结果对象</param>
314        protected void FireCancelEvent(int progress, object result) 
315        { 
316            if( TaskCancel != null ) 
317            { 
318                TaskEventArgs args = new TaskEventArgs( progress,result); 
319                AsyncInvoke(TaskCancel,args);
320            } 
321        } 
322        /** <summary>
323        /// 触发被调用者强行中止事件
324        /// </summary>
325        /// <param name="progress">任务进度(0-100)</param>
326        /// <param name="result">任务工作中间结果对象</param>
327        protected void FireAbortEvent(int progress, object result) 
328        { 
329            if( TaskAbort != null ) 
330            { 
331                TaskEventArgs args = new TaskEventArgs( progress,result); 
332                AsyncInvoke(TaskAbort,args);
333            } 
334        } 
335        /** <summary>
336        /// 异步调用挂接事件委托
337        /// </summary>
338        /// <param name="eventhandler">事件处理方法句柄</param>
339        /// <param name="args">事件消息</param>
340        protected void AsyncInvoke(TaskEventHandler eventhandler,TaskEventArgs args)
341        {
342//            TaskEventHandler[] tpcs = (TaskEventHandler[])eventhandler.GetInvocationList();
343            Delegate[] tpcs = eventhandler.GetInvocationList();
344            foreach(TaskEventHandler tpc in tpcs)
345            {
346                if ( tpc.Target is System.Windows.Forms.Control ) 
347                { 
348                    Control targetForm = tpc.Target as System.Windows.Forms.Control; 
349                    targetForm.BeginInvoke( tpc,new object[] { this, args } ); 
350                } 
351                else 
352                { 
353                    tpc.BeginInvoke(this, args ,null,null); //异步调用,启动后不管
354                }
355            }        
356        }
357        #endregion
358
359        工作进程管理#region 工作进程管理
360        /** <summary>
361        /// 开启任务默认的工作进程
362        /// [public object Work(params  object[] args )]
363        /// </summary>
364        /// <param name="args">传入的参数数组</param>
365        public bool StartTask( params object[] args ) 
366        { 
367            return StartTask(new TaskDelegate( Work ),args); 
368        } 
369        /** <summary>
370        /// 开启任务的工作进程
371        /// 将开启符合TaskDelegate委托接口的worker工作方法
372        /// </summary>
373        /// <param name="worker">工作方法</param>
374        /// <param name="args">传入的参数数组</param>
375        public bool StartTask(TaskDelegate worker ,params object[] args ) 
376        { 
377            bool result =false;
378            lock( this ) 
379            { 
380                if( IsStop && worker != null ) 
381                { 
382                    _result = null;
383                    _callThread = System.Threading.Thread.CurrentThread;
384                    // 开始工作方法进程,异步开启,传送回调方法
385                    worker.BeginInvoke( args ,new AsyncCallback( EndWorkBack ), worker ); 
386                    // 更新任务工作状态
387                    _taskState = TaskStatus.Running; 
388                    // 触发任务工作状态变化事件
389                    FireStatusChangedEvent( _taskState, null); 
390                    result = true;
391                } 
392            } 
393            return result;
394        } 
395        /** <summary>
396        /// 请求停止任务进程
397        /// 是否停止成功,应看任务工作状态属性TaskState是否为TaskStatus.Stop
398        /// </summary>
399        public bool StopTask() 
400        { 
401            bool result =false;
402            lock( this ) 
403            { 
404                if( _taskState == TaskStatus.Running ) 
405                { 
406                    // 更新任务工作状态 
407                    _taskState = TaskStatus.CancelPending; 
408                    // 触发任务工作状态变化事件
409                    FireStatusChangedEvent( _taskState, _result); 
410                    result = true;
411                } 
412            } 
413            return result;
414        } 
415        /** <summary>
416        /// 强行中止任务的工作线程
417        /// 
418        /// </summary>
419        public bool AbortTask() 
420        { 
421            bool result = false;
422            lock( this ) 
423            { 
424                if( _taskState == TaskStatus.Running && _workThread != null ) 
425                { 
426                    if (_workThread.ThreadState != System.Threading.ThreadState.Stopped)
427                    {
428                        _workThread.Abort();
429                    }
430                    System.Threading.Thread.Sleep(2);
431                    if (_workThread.ThreadState == System.Threading.ThreadState.Stopped)
432                    {
433                        // 更新任务工作状态 
434                        _taskState = TaskStatus.Aborted; 
435                        result = true;
436                    }
437                    else
438                    {
439                        // 更新任务工作状态 
440                        _taskState = TaskStatus.AbortPending; 
441                        result = false;
442                    }
443                    // 触发任务工作状态变化事件
444                    FireStatusChangedEvent( _taskState, _result); 
445                } 
446            } 
447            return result;
448        } 
449
450        /** <summary>
451        /// 工作方法完成后的回调方法
452        /// 将检查是否出错,并获取、更新返回结果值
453        /// </summary>
454        /// <param name="ar">异步调用信号对象</param>
455        protected void EndWorkBack( IAsyncResult ar ) 
456        { 
457            bool error = false;
458            bool abort = false;
459            try                                                //检查是否错误
460            {
461                TaskDelegate del = (TaskDelegate)ar.AsyncState; 
462                _result = del.EndInvoke( ar ); 
463            }
464            catch(Exception e)                                //如果错误,则保存错误对象
465            {
466                error = true;
467                _exception = e;
468                if (e.GetType() == typeof(System.Threading.ThreadAbortException))
469                {
470                    abort = true;
471                    FireAbortEvent(_progress,_exception);
472                }
473                else
474                {
475                    FireThrowErrorEvent(_progress,_exception);
476                }
477            }
478            lock( this ) 
479            { 
480                if (error)
481                {
482                    if ( abort)
483                    {
484                        _taskState = TaskStatus.Aborted;        //调用者强行中止
485                    }
486                    else
487                    {
488                        _taskState = TaskStatus.ThrowErrorStoped;//出现错误而中止
489                    }
490                } 
491                else
492                {    _taskState = TaskStatus.Stopped;}          //正常结束
493                FireStatusChangedEvent( _taskState, _result);
494            } 
495        } 
496        #endregion
497
498        工作方法的基础#region 工作方法的基础
499        /** <summary>
500        /// 工作方法
501        /// 在继承类中应重写(override)此方法,以实现具体的工作内容,注意以几点:
502        /// 1.须在继承类是引用base.Work,在基类(base)的Work方法中,执行线程设为IsBackground=true,并保存工作线程对象
503        /// 2.在继承类中,应及时更新_progress与_result对象,以使Progress和Result属性值正确
504        /// 3.在执行过程中应检查_taskState,以使任务中被请求停止后(_taskState为TaskStatus.CancelPending),工作线程能最快终止.
505        /// 4.如在继承类中新定义了事件,应在此方法中引用触发
506        /// 5.工作线程状态不由工作方法管理,所以在工作方法中不应改变_taskState变量值
507        /// 6.工作方法中应对args参数进行有效检查
508        /// </summary>
509        /// <param name="args">传入的参数数组</param>
510        /// <returns>返回null</returns>
511        virtual public object Work(params  object[] args )
512        {
513            System.Threading.Thread.CurrentThread.IsBackground = true;
514            _workThread = System.Threading.Thread.CurrentThread;
515            _result = null;
516            return null;
517        }
518
519        #endregion
520    }
521}
522
523使用Task类#region 使用Task类
524/**//*
525
526使用 Task 类
527
528一.在UI线程中创建Task类
529
530Task 类负责管理后台线程。要使用 Task 类,必须做的事情就是创建一个 Task 对象,注册它激发的事件,并且实现这些事件的处理。因为事件是在 UI 线程上激发的,所以您根本不必担心代码中的线程处理问题。
531
532下面的示例展示了如何创建 Task 对象。现假设UI 有两个按钮,一个用于启动运算,一个用于停止运算,还有一个进度栏显示当前的计算进度。
533
534// 创建任务管理对象
535_Task = new Task(); 
536// 挂接任务管理对象工作状态变化事件
537_Task.TaskStatusChanged += new TaskEventHandler( OnTaskStatusChanged ); 
538// 挂接任务管理对象工作进度变化事件
539_Task.TaskProgressChanged += new TaskEventHandler( OnTaskProgressChanged ); 
540
541(1)
542用于计算状态和计算进度事件的事件处理程序相应地更新 UI,例如通过更新状态栏控件。 
543
544private void OnTaskProgressChanged( object sender,TaskEventArgs e ) 
545{ 
546    _progressBar.Value = e.Progress; 
547} 
548(2)
549下面的代码展示的 TaskStatusChanged 事件处理程序更新进度栏的值以反映当前的计算进度。假定进度栏的最小值和最大值已经初始化。
550
551private void OnTaskStatusChanged( object sender, TaskEventArgs e ) 
552{ 
553    switch ( e.Status ) 
554    { 
555        case TaskStatus.Running: 
556            button1.Enabled = false; 
557            button2.Enabled = true; 
558            break; 
559        case TaskStatus.Stop: 
560            button1.Enabled = true; 
561            button2.Enabled = false; 
562            break; 
563        case TaskStatus.CancelPending: 
564            button1.Enabled = false; 
565            button2.Enabled = false; 
566            break; 
567    } 
568} 
569
570在这个示例中,TaskStatusChanged 事件处理程序根据计算状态启用和禁用启动和停止按钮。这可以防止用户尝试启动一个已经在进行的计算,并且向用户提供有关计算状态的反馈。
571
572通过使用 Task 对象中的公共方法,UI 为每个按钮单击实现了窗体事件处理程序,以便启动和停止计算。例如,启动按钮事件处理程序调用 StartTask 方法,如下所示。
573
574private void startButton_Click( object sender, System.EventArgs e ) 
575{ 
576    _Task.StartTask( new object[] {} ); 
577} 
578
579类似地,停止计算按钮通过调用 StopTask 方法来停止计算,如下所示。
580
581private void stopButton_Click( object sender, System.EventArgs e ) 
582{ 
583    _Task.StopTask(); 
584} 
585
586二.可能在非UI线程中使用Task类时
587(1)和(2)应作如下改变
588
589(1)
590用于计算状态和计算进度事件的事件处理程序相应地更新 UI,例如通过更新状态栏控件。 
591
592private void OnTaskProgressChanged( object sender,TaskEventArgs e ) 
593{ 
594    if (InvokeRequired )        //不在UI线程上,异步调用
595    {
596        TaskEventHandler TPChanged = new TaskEventHandler( OnTaskProgressChanged ); 
597        this.BeginInvoke(TPChanged,new object[] {sender,e});
598    }
599    else                        //更新
600    {
601        _progressBar.Value = e.Progress; 
602    }
603} 
604(2)
605下面的代码展示的 TaskStatusChanged 事件处理程序更新进度栏的值以反映当前的计算进度。假定进度栏的最小值和最大值已经初始化。
606
607private void OnTaskStatusChanged( object sender, TaskEventArgs e ) 
608{ 
609    if (InvokeRequired )        //不在UI线程上,异步调用
610    {
611        TaskEventHandler TSChanged = new TaskEventHandler( OnTaskStatusChanged ); 
612        this.BeginInvoke(TSChanged,new object[] {sender,e});
613    }
614    else                        //更新
615    {
616        switch ( e.Status ) 
617        { 
618            case TaskStatus.Running: 
619                button1.Enabled = false; 
620                button2.Enabled = true; 
621                break; 
622            case TaskStatus.Stop: 
623                button1.Enabled = true; 
624                button2.Enabled = false; 
625                break; 
626            case TaskStatus.CancelPending: 
627                button1.Enabled = false; 
628                button2.Enabled = false; 
629                break; 
630        } 
631    }
632} 
633
634*/
635#endregion
636


三、示例
1.启动时的UI界面
 

2.后台工作方法(费用方法)运行后,任务状态为Running
 

3.强制中止工作方法,运行任务状态Aborted
 

4.工作方法突发错误时,任务状态ThrowErrorStoped
 

5.工作方法正常结束或正常取消而结束时,任务状态Stopped
 

示例代码下载

 


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/vainnetwork/archive/2007/10/19/1833539.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值