转:http://www.cnblogs.com/net66/archive/2005/08/03/206132.html
一、引言
在编写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 )方便调用。在实际使用时,可在继承类中定义多个相同调用接口的方法,避免重复编码,较为方便。
给大家作个参考,而大牛呢,多点指正。当是扔个砖头,想砸块玉吧。
二、代码
1
using System;
2
using System.Windows.Forms;
3
4
namespace Net66.AsynchThread
5![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
6![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
7
/// 任务工作状态
8
/// </summary>
9
public enum TaskStatus
10![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
11![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
12
/// 任务没有运行,可能是工作进程没有开始、工作进程正常结束或正常取消工作进程
13
/// </summary>
14
Stopped,
15![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
16
/// 任务没有运行,被调用者强行中止
17
/// </summary>
18
Aborted,
19![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
20
/// 任务没有运行,在工作进程中触发错误而中止
21
/// </summary>
22
ThrowErrorStoped,
23![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
24
/// 任务运行中
25
/// </summary>
26
Running,
27![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
28
/// 尝试取消工作进程中
29
/// </summary>
30
CancelPending,
31![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
32
/// 强行中止工作进程中
33
/// </summary>
34
AbortPending
35
36
}
37
38![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
39
/// 任务状态消息
40
/// </summary>
41
public class TaskEventArgs : EventArgs
42![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
43![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
44
/// 任务运行结果
45
/// </summary>
46
public Object Result;
47![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
48
/// 任务进度(0-100)
49
/// </summary>
50
public int Progress;
51![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
52
/// 任务工作状态
53
/// </summary>
54
public TaskStatus Status;
55![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
56
/// 任务消息文本
57
/// </summary>
58
public String Message;
59![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
60
/// 创建任务状态消息
61
/// </summary>
62
/// <param name="progress">任务进度(0-100)</param>
63
public TaskEventArgs( int progress )
64![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
65
this.Progress = progress;
66
this.Status = TaskStatus.Running;
67
}
68![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
69
/// 创建任务状态消息
70
/// </summary>
71
/// <param name="status">任务线程状态</param>
72
public TaskEventArgs( TaskStatus status )
73![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
74
this.Status = status;
75
}
76![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
77
/// 创建任务状态消息
78
/// </summary>
79
/// <param name="progress">任务进度(0-100)</param>
80
/// <param name="result">任务运行中间结果</param>
81
public TaskEventArgs( int progress,object result )
82![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
83
this.Progress = progress;
84
this.Status = TaskStatus.Running;
85
this.Result = result;
86
}
87![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
88
/// 创建任务状态消息
89
/// </summary>
90
/// <param name="status">任务线程状态</param>
91
/// <param name="result">任务运行结果</param>
92
public TaskEventArgs( TaskStatus status,object result )
93![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
94
this.Status = status;
95
this.Result = result;
96
}
97![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
105
this.Status = status;
106
this.Message = message;
107
this.Result = result;
108
}
109![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
117
this.Progress = progress;
118
this.Status = TaskStatus.Running;
119
this.Message = message;
120
this.Result = result;
121
}
122![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
131
this.Status = status;
132
this.Progress = progress;
133
this.Message = message;
134
this.Result = result;
135
}
136
}
137
138![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
139
/// 任务的工作方法(Work)的委托接口
140
/// 传入值:对象数组(object[])
141
/// 返回值:对象(object)
142
/// </summary>
143
public delegate object TaskDelegate( params object[] args );
144
145![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
146
/// 任务事件的委托接口
147
/// </summary>
148
public delegate void TaskEventHandler( object sender, TaskEventArgs e );
149
150
abstract public class Task
151![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
152![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
内部属性#region 内部属性
153![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
154
/// 任务调用线程(前台或UI线程)
155
/// </summary>
156
protected System.Threading.Thread _callThread = null;
157![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
158
/// 任务工作线程(后台)
159
/// </summary>
160
protected System.Threading.Thread _workThread = null;
161![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
162
/// 任务工作状态
163
/// </summary>
164
protected TaskStatus _taskState = TaskStatus.Stopped;
165![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
166
/// 任务进度(0-100)
167
/// </summary>
168
protected int _progress = -1;
169![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
170
/// 任务工作结果
171
/// </summary>
172
protected object _result = null;
173![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
174
/// 任务工作进程出错时,捕获的异常对象
175
/// </summary>
176
protected Exception _exception = null;
177
#endregion
178
179![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
事件#region 事件
180![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
181
/// 任务工作状态变化事件
182
/// </summary>
183
public event TaskEventHandler TaskStatusChanged;
184![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
185
/// 任务进度变化事件
186
/// </summary>
187
public event TaskEventHandler TaskProgressChanged;
188![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
189
/// 任务被调用者强行中止事件
190
/// </summary>
191
public event TaskEventHandler TaskAbort;
192![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
193
/// 任务工作方法执行中触发错误事件
194
/// </summary>
195
public event TaskEventHandler TaskThrowError;
196![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
197
/// 任务被调用者取消事件
198
/// </summary>
199
public event TaskEventHandler TaskCancel;
200
#endregion
201
202![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
属性#region 属性
203
204![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
205
/// 任务工作进程出错时,捕获的异常对象
206
/// </summary>
207
public Exception Exception
208![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
209![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _exception;}
210
}
211![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
212
/// 任务调用线程(前台或UI线程)
213
/// </summary>
214
public System.Threading.Thread CallThread
215![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
216![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{ return _callThread;}
217
}
218![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
219
/// 任务工作线程(后台)
220
/// </summary>
221
public System.Threading.Thread WordThread
222![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
223![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{return _workThread;}
224
}
225
226![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
227
/// 任务进度(0-100)
228
/// </summary>
229
public int Progress
230![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
231![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{return _progress;}
232
}
233![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
234
/// 任务工作状态
235
/// </summary>
236
public TaskStatus TaskState
237![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
238![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{return _taskState;}
239
}
240![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
241
/// 任务工作结果
242
/// </summary>
243
public object Result
244![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
245![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
get
{return _result;}
246
}
247
248
protected bool IsStop
249![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
250
get
251![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
252
bool result = false;
253
switch (_taskState)
254![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
触发事件#region 触发事件
269![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
270
/// 触发任务工作状态变化事件
271
/// </summary>
272
/// <param name="status">任务工作状态</param>
273
/// <param name="result">任务工作结果对象</param>
274
protected void FireStatusChangedEvent(TaskStatus status, object result)
275![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
276
if( TaskStatusChanged != null )
277![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
278
TaskEventArgs args = new TaskEventArgs( status,result);
279
AsyncInvoke(TaskStatusChanged,args);
280
}
281
}
282
283![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
290
if( TaskProgressChanged != null )
291![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
292
TaskEventArgs args = new TaskEventArgs( progress,result);
293
AsyncInvoke(TaskProgressChanged,args);
294
}
295
}
296![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
303
if( TaskThrowError != null )
304![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
305
TaskEventArgs args = new TaskEventArgs( progress,result);
306
AsyncInvoke(TaskThrowError,args);
307
}
308
}
309![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
316
if( TaskCancel != null )
317![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
318
TaskEventArgs args = new TaskEventArgs( progress,result);
319
AsyncInvoke(TaskCancel,args);
320
}
321
}
322![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
329
if( TaskAbort != null )
330![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
331
TaskEventArgs args = new TaskEventArgs( progress,result);
332
AsyncInvoke(TaskAbort,args);
333
}
334
}
335![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
336
/// 异步调用挂接事件委托
337
/// </summary>
338
/// <param name="eventhandler">事件处理方法句柄</param>
339
/// <param name="args">事件消息</param>
340
protected void AsyncInvoke(TaskEventHandler eventhandler,TaskEventArgs args)
341![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
342
// TaskEventHandler[] tpcs = (TaskEventHandler[])eventhandler.GetInvocationList();
343
Delegate[] tpcs = eventhandler.GetInvocationList();
344
foreach(TaskEventHandler tpc in tpcs)
345![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
346
if ( tpc.Target is System.Windows.Forms.Control )
347![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
348
Control targetForm = tpc.Target as System.Windows.Forms.Control;
349![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
targetForm.BeginInvoke( tpc,new object[]
{ this, args } );
350
}
351
else
352![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
353
tpc.BeginInvoke(this, args ,null,null); //异步调用,启动后不管
354
}
355
}
356
}
357
#endregion
358
359![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
工作进程管理#region 工作进程管理
360![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
361
/// 开启任务默认的工作进程
362
/// [public object Work(params object[] args )]
363
/// </summary>
364
/// <param name="args">传入的参数数组</param>
365
public bool StartTask( params object[] args )
366![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
367
return StartTask(new TaskDelegate( Work ),args);
368
}
369![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
377
bool result =false;
378
lock( this )
379![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
380
if( IsStop && worker != null )
381![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
396
/// 请求停止任务进程
397
/// 是否停止成功,应看任务工作状态属性TaskState是否为TaskStatus.Stop
398
/// </summary>
399
public bool StopTask()
400![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
401
bool result =false;
402
lock( this )
403![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
404
if( _taskState == TaskStatus.Running )
405![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
406
// 更新任务工作状态
407
_taskState = TaskStatus.CancelPending;
408
// 触发任务工作状态变化事件
409
FireStatusChangedEvent( _taskState, _result);
410
result = true;
411
}
412
}
413
return result;
414
}
415![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
416
/// 强行中止任务的工作线程
417
///
418
/// </summary>
419
public bool AbortTask()
420![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
421
bool result = false;
422
lock( this )
423![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
424
if( _taskState == TaskStatus.Running && _workThread != null )
425![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
426
if (_workThread.ThreadState != System.Threading.ThreadState.Stopped)
427![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
428
_workThread.Abort();
429
}
430
System.Threading.Thread.Sleep(2);
431
if (_workThread.ThreadState == System.Threading.ThreadState.Stopped)
432![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
433
// 更新任务工作状态
434
_taskState = TaskStatus.Aborted;
435
result = true;
436
}
437
else
438![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
439
// 更新任务工作状态
440
_taskState = TaskStatus.AbortPending;
441
result = false;
442
}
443
// 触发任务工作状态变化事件
444
FireStatusChangedEvent( _taskState, _result);
445
}
446
}
447
return result;
448
}
449
450![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <summary>
451
/// 工作方法完成后的回调方法
452
/// 将检查是否出错,并获取、更新返回结果值
453
/// </summary>
454
/// <param name="ar">异步调用信号对象</param>
455
protected void EndWorkBack( IAsyncResult ar )
456![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
457
bool error = false;
458
bool abort = false;
459
try //检查是否错误
460![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
461
TaskDelegate del = (TaskDelegate)ar.AsyncState;
462
_result = del.EndInvoke( ar );
463
}
464
catch(Exception e) //如果错误,则保存错误对象
465![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
466
error = true;
467
_exception = e;
468
if (e.GetType() == typeof(System.Threading.ThreadAbortException))
469![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
470
abort = true;
471
FireAbortEvent(_progress,_exception);
472
}
473
else
474![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
475
FireThrowErrorEvent(_progress,_exception);
476
}
477
}
478
lock( this )
479![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
480
if (error)
481![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
482
if ( abort)
483![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
484
_taskState = TaskStatus.Aborted; //调用者强行中止
485
}
486
else
487![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
488
_taskState = TaskStatus.ThrowErrorStoped;//出现错误而中止
489
}
490
}
491
else
492![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{ _taskState = TaskStatus.Stopped;} //正常结束
493
FireStatusChangedEvent( _taskState, _result);
494
}
495
}
496
#endregion
497
498![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
工作方法的基础#region 工作方法的基础
499![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//// <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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
使用Task类#region 使用Task类
524![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//*
525
526
使用 Task 类
527
528
一.在UI线程中创建Task类
529
530
Task 类负责管理后台线程。要使用 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
544
private void OnTaskProgressChanged( object sender,TaskEventArgs e )
545
{
546
_progressBar.Value = e.Progress;
547
}
548
(2)
549
下面的代码展示的 TaskStatusChanged 事件处理程序更新进度栏的值以反映当前的计算进度。假定进度栏的最小值和最大值已经初始化。
550
551
private 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
574
private void startButton_Click( object sender, System.EventArgs e )
575
{
576
_Task.StartTask( new object[] {} );
577
}
578
579
类似地,停止计算按钮通过调用 StopTask 方法来停止计算,如下所示。
580
581
private 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
592
private 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
607
private 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
示例代码下载
评论
#1楼 2005-08-03 00:50 idior
#2楼 2005-08-03 01:50 木野狐
#3楼 218.81.148.* 2005-08-03 07:11 gogo [未注册用户]
#4楼 218.249.96.* 2005-08-03 08:46 Nineteen@newsmth [未注册用户]
#5楼 222.43.70.* 2005-08-03 08:49 学习 [未注册用户]
#6楼 2005-08-03 08:54 James
#7楼 222.47.87.* 2005-08-03 09:06 张老三 [未注册用户]
#8楼 218.79.240.* 2005-08-03 09:08 win [未注册用户]
#9楼 2005-08-03 09:23 BearTang
#10楼 2005-08-03 09:39 妖居
#11楼 2005-08-03 09:41 James
#12楼 2005-08-03 18:48 yinh
#13楼 2005-09-12 18:34 沧海一声笑
太好了 还有源码,可以少走一些弯路了
谢谢!
#14楼 2005-09-14 16:10 双鱼座
先搞清楚你的Task的派生类依赖什么,也就是说可供派生类调用的方法,例如Fire***方法;接下来搞清楚你的Task的派生类不依赖什么,例如必须在重写方法中调用base.Work这样的问题;最后是参数的传递问题。由此我想到了在Delphi3中对Thread的封装,有一个同步执行方法的方法,在调用者不知道任何细节的情况下可以进行安全的调用。当然,那个封装代价有点大了。
我作了如下修改:
1.定义一个抽象方法:
protected abstract object Execute(params object [] args);
这个方法才是真正需要继承的方法。
2.基类的Work方法改成私有方法(Work这个名字取得不是太好),代码这样写:
System.Threading.Thread.CurrentThread.IsBackground = true;
_workThread = System.Threading.Thread.CurrentThread;
return Execute(args);
3.加一个线程方法:
void start()
{
StartTask(new TaskDelegate(Work), tempArgs);
}
4.定义一个私有字段用来向线程传递参数:
private object[] tempArgs;
5.最后加一个启动方法:
public void Start(params object[] args)
{
tempArgs = args;
Thread thread = new Thread(new ThreadStart(start));
thread.Start();
}
改造完成了。客户端代码由此变得非常简洁:
1.当按下“开始执行”时的代码:
_Task.Start(new object[] {});
2.Concrete类型newasynchui的代码也简单了,只需要重写一个Execute方法而不是重载一个Work和另外写一个Work2,在方法中也不必调用base.Work,你想调用也调用不了,因为是那是私有方法。
当然还有其它一些更好的建议,例如不必定义那么多的事件,其实一两个就足够了,也不需要派生新的EventArgs类型,因为从sender中可以获得所有的信息。
我的解决方案可能更邪一点了,因为我是用反射和Emit实现的,原理和你的差不多,只不过客户端代码可以非常简单而已。
#15楼 218.81.143.* 2005-09-14 20:59 net66
我想你的解决方案一定相当不错,能否Mail一份,学习探讨探讨.the8341 at gmail.com
#16楼 2005-09-19 11:19 双鱼座
呵呵,OK,这两天我整理一下也写篇文章和你分享。
#17楼 218.79.244.* 2005-09-19 11:36 net66
:-) 好文共享,期待中
#18楼 2005-09-19 17:35 双鱼座
#19楼 [楼主] 2005-09-20 09:10 Net66
http://www.cnblogs.com/Barton131420/articles/239855.html
#20楼 222.82.56.* 2006-10-07 16:37 可乐[匿名] [未注册用户]
#21楼 58.241.234.* 2007-05-04 15:07 小雨 [未注册用户]
#22楼 2007-07-19 13:33 yellowyu
#23楼 2008-01-10 10:56 蓝天旭日
#24楼 2008-03-21 21:45 程之恒
#25楼 222.20.100.* 2008-08-19 17:54 娄玲 [未注册用户]