衔接UI线程和管理后台工作线程的类(多线程、异步调用)

来源:互联网 发布:mac ipconfig 命令 编辑:程序博客网 时间:2024/05/06 03:08
一、引言 
     在编写Windows form时,如果直接在UI线程要运行一个费时方法的话(如从数据库查询大量数据时),会引起程序“假死”,从而导致用户不满。这个时候就需要通过多线程技术来解决,提高界面交互性能,方便用户使用。 

一般通过三种方式解决: 

1.通过System.Threading.Thread类,创建新的线程,Thread.Start运行费时方法。 
2.通过System.Threading.ThreadPool类,将费时任务提交到线程池中,等待运行。 
以上两种方法,基本思路是在UI界面中控制线程的启动和中止,在线程中回调用UI界面方法,更新界面。在线程中回调UI界面方法时,特别是涉及更新控件属性时,如果不注意,存在很大的隐患。这两种办法,编码和控制结构较为复杂,需要启动和管理额外的线程占用资源。 
3.通过异步委托调用,将该方法排队到系统线程池的线程中运行,而在费时方法中也通过Control.BeginInvoke异步回调,达到"启动后不管"的目的。 
这种方法,编码简单,程序结构较为清晰,充分利用.NET框架的异步委托功能,但要对异步调用知识较熟悉。 

相关知识点参见 
http://net66.cnblogs.com/net66/admin/archive/2005/08/02/206067.html
     现利用.NET异步委托调用功能,编写Task抽象类,以方便管理后台工作线程,衔接后台线程与UI线程的联系。该抽象类提供了调用和管理的框架,没有方法的实现细节,通过继承类、重写方法,
可以实现想要的功能。主要功能如下: 

1.利用异步委托调用,实际多线程,不需要单独后台线程。 
2.通过委托、事件驱动,实际后台与前台UI线程的联系,实现事件广播。 
3.支持正常取消后台工作方法(费时方法)运行,也可以强制中止线程。 
4.能够捕获取消、强制中止和方法出错三种情况,并突发相关事件,以便进行释放资源等操作。 
5.通过异步调用,在工作方法中安全调用涉及UI控件的方法。 
6.自行管理工作进程状态,提供状态变化事件。 
7.只要工作方法调用签名,符合定义的TaskDelegate委托接口,可通过StartTask(TaskDelegate worker ,params object[] args )方便调用。在实际使用时,可在继承类中定义多个相同调用接口的方法,避免重复编码,较为方便。 

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

二、代码
using System;using System.Windows.Forms;namespace Net66.AsynchThread{    /// <summary>     /// 任务工作状态     /// </summary>     public enum TaskStatus    {        /// <summary>         /// 任务没有运行,可能是工作进程没有开始、工作进程正常结束或正常取消工作进程         /// </summary>         Stopped,        /// <summary>         /// 任务没有运行,被调用者强行中止         /// </summary>         Aborted,        /// <summary>         /// 任务没有运行,在工作进程中触发错误而中止         /// </summary>         ThrowErrorStoped,        /// <summary>         /// 任务运行中         /// </summary>         Running,        /// <summary>         /// 尝试取消工作进程中         /// </summary>         CancelPending,        /// <summary>         /// 强行中止工作进程中         /// </summary>         AbortPending    }    /// <summary>     /// 任务状态消息     /// </summary>     public class TaskEventArgs : EventArgs    {        /// <summary>         /// 任务运行结果         /// </summary>         public Object Result;        /// <summary>         /// 任务进度(0-100)         /// </summary>         public int Progress;        /// <summary>         /// 任务工作状态         /// </summary>         public TaskStatus Status;        /// <summary>         /// 任务消息文本         /// </summary>         public String Message;        /// <summary>         /// 创建任务状态消息         /// </summary>         /// <param name="progress">任务进度(0-100)</param>         public TaskEventArgs(int progress)        {            this.Progress = progress;            this.Status = TaskStatus.Running;        }        /// <summary>         /// 创建任务状态消息         /// </summary>         /// <param name="status">任务线程状态</param>         public TaskEventArgs(TaskStatus status)        {            this.Status = status;        }        /// <summary>         /// 创建任务状态消息         /// </summary>         /// <param name="progress">任务进度(0-100)</param>         /// <param name="result">任务运行中间结果</param>         public TaskEventArgs(int progress, object result)        {            this.Progress = progress;            this.Status = TaskStatus.Running;            this.Result = result;        }        /// <summary>         /// 创建任务状态消息         /// </summary>         /// <param name="status">任务线程状态</param>         /// <param name="result">任务运行结果</param>         public TaskEventArgs(TaskStatus status, object result)        {            this.Status = status;            this.Result = result;        }        /// <summary>         /// 创建任务状态消息         /// </summary>         /// <param name="status">任务线程状态</param>         /// <param name="message">消息文本</param>         /// <param name="result">任务运行结果</param>         public TaskEventArgs(TaskStatus status, string message, object result)        {            this.Status = status;            this.Message = message;            this.Result = result;        }        /// <summary>         /// 创建任务状态消息         /// </summary>         /// <param name="progress">任务进度(0-100)</param>         /// <param name="message">消息文本</param>         /// <param name="result">任务运行中间结果</param>         public TaskEventArgs(int progress, string message, object result)        {            this.Progress = progress;            this.Status = TaskStatus.Running;            this.Message = message;            this.Result = result;        }        /// <summary>         /// 创建任务状态消息         /// </summary>         /// <param name="status">任务线程状态</param>         /// <param name="progress">任务进度(0-100)</param>         /// <param name="message">消息文本</param>         /// <param name="result">任务运行中间结果</param>         public TaskEventArgs(TaskStatus status, int progress, string message, object result)        {            this.Status = status;            this.Progress = progress;            this.Message = message;            this.Result = result;        }    }    /// <summary>     /// 任务的工作方法(Work)的委托接口     /// 传入值:对象数组(object[])     /// 返回值:对象(object)     /// </summary>     public delegate object TaskDelegate(params object[] args);    /// <summary>     /// 任务事件的委托接口     /// </summary>     public delegate void TaskEventHandler(object sender, TaskEventArgs e);    abstract public class Task    {        #region 内部属性        /// <summary>         /// 任务调用线程(前台或UI线程)         /// </summary>         protected System.Threading.Thread _callThread = null;        /// <summary>         /// 任务工作线程(后台)         /// </summary>         protected System.Threading.Thread _workThread = null;        /// <summary>         /// 任务工作状态         /// </summary>         protected TaskStatus _taskState = TaskStatus.Stopped;        /// <summary>         /// 任务进度(0-100)         /// </summary>         protected int _progress = -1;        /// <summary>         /// 任务工作结果         /// </summary>         protected object _result = null;        /// <summary>         /// 任务工作进程出错时,捕获的异常对象         /// </summary>         protected Exception _exception = null;        #endregion        #region 事件        /// <summary>         /// 任务工作状态变化事件         /// </summary>         public event TaskEventHandler TaskStatusChanged;        /// <summary>         /// 任务进度变化事件         /// </summary>         public event TaskEventHandler TaskProgressChanged;        /// <summary>         /// 任务被调用者强行中止事件         /// </summary>         public event TaskEventHandler TaskAbort;        /// <summary>         /// 任务工作方法执行中触发错误事件         /// </summary>         public event TaskEventHandler TaskThrowError;        /// <summary>         /// 任务被调用者取消事件         /// </summary>         public event TaskEventHandler TaskCancel;        #endregion        #region 属性        /// <summary>         /// 任务工作进程出错时,捕获的异常对象         /// </summary>         public Exception Exception        {            get { return _exception; }        }        /// <summary>         /// 任务调用线程(前台或UI线程)         /// </summary>         public System.Threading.Thread CallThread        {            get { return _callThread; }        }        /// <summary>         /// 任务工作线程(后台)         /// </summary>         public System.Threading.Thread WordThread        {            get { return _workThread; }        }        /// <summary>         /// 任务进度(0-100)         /// </summary>         public int Progress        {            get { return _progress; }        }        /// <summary>         /// 任务工作状态         /// </summary>         public TaskStatus TaskState        {            get { return _taskState; }        }        /// <summary>         /// 任务工作结果         /// </summary>         public object Result        {            get { return _result; }        }        protected bool IsStop        {            get            {                bool result = false;                switch (_taskState)                {                case TaskStatus.Stopped:                case TaskStatus.Aborted:                case TaskStatus.ThrowErrorStoped:                    result = true;                    break;                default:                    break;                }                return result;            }        }        #endregion        #region 触发事件        /// <summary>         /// 触发任务工作状态变化事件         /// </summary>         /// <param name="status">任务工作状态</param>         /// <param name="result">任务工作结果对象</param>         protected void FireStatusChangedEvent(TaskStatus status, object result)        {            if (TaskStatusChanged != null)            {                TaskEventArgs args = new TaskEventArgs(status, result);                AsyncInvoke(TaskStatusChanged, args);            }        }        /// <summary>         /// 触发任务进度变化事件         /// </summary>         /// <param name="progress">任务进度(0-100)</param>         /// <param name="result">任务工作中间结果对象</param>         protected void FireProgressChangedEvent(int progress, object result)        {            if (TaskProgressChanged != null)            {                TaskEventArgs args = new TaskEventArgs(progress, result);                AsyncInvoke(TaskProgressChanged, args);            }        }        /// <summary>         /// 触发工作方法执行中发现错误事件         /// </summary>         /// <param name="progress">任务进度(0-100)</param>         /// <param name="result">任务工作中间结果对象</param>         protected void FireThrowErrorEvent(int progress, object result)        {            if (TaskThrowError != null)            {                TaskEventArgs args = new TaskEventArgs(progress, result);                AsyncInvoke(TaskThrowError, args);            }        }        /// <summary>         /// 触发被调用者取消事件         /// </summary>         /// <param name="progress">任务进度(0-100)</param>         /// <param name="result">任务工作中间结果对象</param>         protected void FireCancelEvent(int progress, object result)        {            if (TaskCancel != null)            {                TaskEventArgs args = new TaskEventArgs(progress, result);                AsyncInvoke(TaskCancel, args);            }        }        /// <summary>         /// 触发被调用者强行中止事件         /// </summary>         /// <param name="progress">任务进度(0-100)</param>         /// <param name="result">任务工作中间结果对象</param>         protected void FireAbortEvent(int progress, object result)        {            if (TaskAbort != null)            {                TaskEventArgs args = new TaskEventArgs(progress, result);                AsyncInvoke(TaskAbort, args);            }        }        /// <summary>         /// 异步调用挂接事件委托         /// </summary>         /// <param name="eventhandler">事件处理方法句柄</param>         /// <param name="args">事件消息</param>         protected void AsyncInvoke(TaskEventHandler eventhandler, TaskEventArgs args)        {            //            TaskEventHandler[] tpcs = (TaskEventHandler[])eventhandler.GetInvocationList();             Delegate[] tpcs = eventhandler.GetInvocationList();            foreach (TaskEventHandler tpc in tpcs)            {                if (tpc.Target is System.Windows.Forms.Control)                {                    Control targetForm = tpc.Target as System.Windows.Forms.Control;                    targetForm.BeginInvoke(tpc, new object[] { this, args });                }                else                {                    tpc.BeginInvoke(this, args, null, null); //异步调用,启动后不管                 }            }        }        #endregion        #region 工作进程管理        /// <summary>         /// 开启任务默认的工作进程         /// [public object Work(params  object[] args )]         /// </summary>         /// <param name="args">传入的参数数组</param>         public bool StartTask(params object[] args)        {            return StartTask(new TaskDelegate(Work), args);        }        /// <summary>         /// 开启任务的工作进程         /// 将开启符合TaskDelegate委托接口的worker工作方法         /// </summary>         /// <param name="worker">工作方法</param>         /// <param name="args">传入的参数数组</param>         public bool StartTask(TaskDelegate worker, params object[] args)        {            bool result = false;            lock (this)            {                if (IsStop && worker != null)                {                    _result = null;                    _callThread = System.Threading.Thread.CurrentThread;                    // 开始工作方法进程,异步开启,传送回调方法                     worker.BeginInvoke(args, new AsyncCallback(EndWorkBack), worker);                    // 更新任务工作状态                     _taskState = TaskStatus.Running;                    // 触发任务工作状态变化事件                     FireStatusChangedEvent(_taskState, null);                    result = true;                }            }            return result;        }        /// <summary>         /// 请求停止任务进程         /// 是否停止成功,应看任务工作状态属性TaskState是否为TaskStatus.Stop         /// </summary>         public bool StopTask()        {            bool result = false;            lock (this)            {                if (_taskState == TaskStatus.Running)                {                    // 更新任务工作状态                      _taskState = TaskStatus.CancelPending;                    // 触发任务工作状态变化事件                     FireStatusChangedEvent(_taskState, _result);                    result = true;                }            }            return result;        }        /// <summary>         /// 强行中止任务的工作线程         ///          /// </summary>         public bool AbortTask()        {            bool result = false;            lock (this)            {                if (_taskState == TaskStatus.Running && _workThread != null)                {                    if (_workThread.ThreadState != System.Threading.ThreadState.Stopped)                    {                        _workThread.Abort();                    }                    System.Threading.Thread.Sleep(2);                    if (_workThread.ThreadState == System.Threading.ThreadState.Stopped)                    {                        // 更新任务工作状态                          _taskState = TaskStatus.Aborted;                        result = true;                    }                    else                    {                        // 更新任务工作状态                          _taskState = TaskStatus.AbortPending;                        result = false;                    }                    // 触发任务工作状态变化事件                     FireStatusChangedEvent(_taskState, _result);                }            }            return result;        }        /// <summary>         /// 工作方法完成后的回调方法         /// 将检查是否出错,并获取、更新返回结果值         /// </summary>         /// <param name="ar">异步调用信号对象</param>         protected void EndWorkBack(IAsyncResult ar)        {            bool error = false;            bool abort = false;            try                                                //检查是否错误             {                TaskDelegate del = (TaskDelegate) ar.AsyncState;                _result = del.EndInvoke(ar);            }            catch (Exception e)                                //如果错误,则保存错误对象             {                error = true;                _exception = e;                if (e.GetType() == typeof(System.Threading.ThreadAbortException))                {                    abort = true;                    FireAbortEvent(_progress, _exception);                }                else                {                    FireThrowErrorEvent(_progress, _exception);                }            }            lock (this)            {                if (error)                {                    if (abort)                    {                        _taskState = TaskStatus.Aborted;        //调用者强行中止                     }                    else                    {                        _taskState = TaskStatus.ThrowErrorStoped;//出现错误而中止                     }                }                else                { _taskState = TaskStatus.Stopped; }          //正常结束                 FireStatusChangedEvent(_taskState, _result);            }        }        #endregion        #region 工作方法的基础        /// <summary>         /// 工作方法         /// 在继承类中应重写(override)此方法,以实现具体的工作内容,注意以几点:         /// 1.须在继承类是引用base.Work,在基类(base)的Work方法中,执行线程设为IsBackground=true,并保存工作线程对象         /// 2.在继承类中,应及时更新_progress与_result对象,以使Progress和Result属性值正确         /// 3.在执行过程中应检查_taskState,以使任务中被请求停止后(_taskState为TaskStatus.CancelPending),工作线程能最快终止.         /// 4.如在继承类中新定义了事件,应在此方法中引用触发         /// 5.工作线程状态不由工作方法管理,所以在工作方法中不应改变_taskState变量值         /// 6.工作方法中应对args参数进行有效检查         /// </summary>         /// <param name="args">传入的参数数组</param>         /// <returns>返回null</returns>         virtual public object Work(params  object[] args)        {            System.Threading.Thread.CurrentThread.IsBackground = true;            _workThread = System.Threading.Thread.CurrentThread;            _result = null;            return null;        }        #endregion    }}

  

使用 Task 类 
 
一.在UI线程中创建Task类 
 
Task 类负责管理后台线程。要使用 Task 类,必须做的事情就是创建一个 Task 对象,注册它激发的事件,并且实现这些事件的处理。因为事件是在 UI 线程上激发的,所以您根本不必担心代码中的线程处理问题。 
 
下面的示例展示了如何创建 Task 对象。现假设UI 有两个按钮,一个用于启动运算,一个用于停止运算,还有一个进度栏显示当前的计算进度。 
// 创建任务管理对象 _Task = new Task();// 挂接任务管理对象工作状态变化事件 _Task.TaskStatusChanged += new TaskEventHandler(OnTaskStatusChanged);// 挂接任务管理对象工作进度变化事件 _Task.TaskProgressChanged += new TaskEventHandler(OnTaskProgressChanged);
 
(1) 
用于计算状态和计算进度事件的事件处理程序相应地更新 UI,例如通过更新状态栏控件。 
private void OnTaskProgressChanged(object sender, TaskEventArgs e){    _progressBar.Value = e.Progress;}
 
(2) 
下面的代码展示的 TaskStatusChanged 事件处理程序更新进度栏的值以反映当前的计算进度。假定进度栏的最小值和最大值已经初始化。 
private void OnTaskStatusChanged(object sender, TaskEventArgs e){    switch (e.Status)    {    case TaskStatus.Running:        button1.Enabled = false;        button2.Enabled = true;        break;    case TaskStatus.Stop:        button1.Enabled = true;        button2.Enabled = false;        break;    case TaskStatus.CancelPending:        button1.Enabled = false;        button2.Enabled = false;        break;    }}
  
在这个示例中,TaskStatusChanged 事件处理程序根据计算状态启用和禁用启动和停止按钮。这可以防止用户尝试启动一个已经在进行的计算,并且向用户提供有关计算状态的反馈。 
 
通过使用 Task 对象中的公共方法,UI 为每个按钮单击实现了窗体事件处理程序,以便启动和停止计算。例如,启动按钮事件处理程序调用 StartTask 方法,如下所示。 
private void startButton_Click(object sender, System.EventArgs e){    _Task.StartTask(new object[] { });}
 
类似地,停止计算按钮通过调用 StopTask 方法来停止计算,如下所示。 
private void stopButton_Click( object sender, System.EventArgs e )  {      _Task.StopTask();  }
 
 
二.可能在非UI线程中使用Task类时 
(1)和(2)应作如下改变 
 
(1) 
用于计算状态和计算进度事件的事件处理程序相应地更新 UI,例如通过更新状态栏控件。  
private void OnTaskProgressChanged(object sender, TaskEventArgs e){    if (InvokeRequired)        //不在UI线程上,异步调用     {        TaskEventHandler TPChanged = new TaskEventHandler(OnTaskProgressChanged);        this.BeginInvoke(TPChanged, new object[] { sender, e });    }    else                        //更新     {        _progressBar.Value = e.Progress;    }}
 
(2) 
下面的代码展示的 TaskStatusChanged 事件处理程序更新进度栏的值以反映当前的计算进度。假定进度栏的最小值和最大值已经初始化。 
private void OnTaskStatusChanged(object sender, TaskEventArgs e){    if (InvokeRequired)        //不在UI线程上,异步调用     {        TaskEventHandler TSChanged = new TaskEventHandler(OnTaskStatusChanged);        this.BeginInvoke(TSChanged, new object[] { sender, e });    }    else                        //更新     {        switch (e.Status)        {        case TaskStatus.Running:            button1.Enabled = false;            button2.Enabled = true;            break;        case TaskStatus.Stop:            button1.Enabled = true;            button2.Enabled = false;            break;        case TaskStatus.CancelPending:            button1.Enabled = false;            button2.Enabled = false;            break;        }    }}
 

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

单击在新窗口中打开图片,Ctrl+滚轮缩放图片

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

单击在新窗口中打开图片,Ctrl+滚轮缩放图片

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

单击在新窗口中打开图片,Ctrl+滚轮缩放图片

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

单击在新窗口中打开图片,Ctrl+滚轮缩放图片

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

单击在新窗口中打开图片,Ctrl+滚轮缩放图片

示例代码下载
http://files.cnblogs.com/net66/asynchui-2.rar  
原创粉丝点击