衔接UI线程和管理后台工作线程的类(多线程、异步调用)
转: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 )方便调用。在实际使用时,可在继承类中定义多个相同调用接口的方法,避免重复编码,较为方便。
给大家作个参考,而大牛呢,多点指正。当是扔个砖头,想砸块玉吧。
二、代码

2

3

4

5



6


7

8

9

10



11


12

13

14

15


16

17

18

19


20

21

22

23


24

25

26

27


28

29

30

31


32

33

34

35

36

37

38


39

40

41

42



43


44

45

46

47


48

49

50

51


52

53

54

55


56

57

58

59


60

61

62

63

64



65

66

67

68


69

70

71

72

73



74

75

76


77

78

79

80

81

82



83

84

85

86

87


88

89

90

91

92

93



94

95

96

97


98

99

100

101

102

103

104



105

106

107

108

109


110

111

112

113

114

115

116



117

118

119

120

121

122


123

124

125

126

127

128

129

130



131

132

133

134

135

136

137

138


139

140

141

142

143

144

145


146

147

148

149

150

151



152


153


154

155

156

157


158

159

160

161


162

163

164

165


166

167

168

169


170

171

172

173


174

175

176

177

178

179


180


181

182

183

184


185

186

187

188


189

190

191

192


193

194

195

196


197

198

199

200

201

202


203

204


205

206

207

208



209



210

211


212

213

214

215



216



217

218


219

220

221

222



223



224

225

226


227

228

229

230



231



232

233


234

235

236

237



238



239

240


241

242

243

244



245



246

247

248

249



250

251



252

253

254



255

256

257

258

259

260

261

262

263

264

265

266

267

268


269


270

271

272

273

274

275



276

277



278

279

280

281

282

283


284

285

286

287

288

289



290

291



292

293

294

295

296


297

298

299

300

301

302



303

304



305

306

307

308

309


310

311

312

313

314

315



316

317



318

319

320

321

322


323

324

325

326

327

328



329

330



331

332

333

334

335


336

337

338

339

340

341



342

343

344

345



346

347



348

349



350

351

352



353

354

355

356

357

358

359


360


361

362

363

364

365

366



367

368

369


370

371

372

373

374

375

376



377

378

379



380

381



382

383

384

385

386

387

388

389

390

391

392

393

394

395


396

397

398

399

400



401

402

403



404

405



406

407

408

409

410

411

412

413

414

415


416

417

418

419

420



421

422

423



424

425



426

427



428

429

430

431

432



433

434

435

436

437

438



439

440

441

442

443

444

445

446

447

448

449

450


451

452

453

454

455

456



457

458

459

460



461

462

463

464

465



466

467

468

469



470

471

472

473

474



475

476

477

478

479



480

481



482

483



484

485

486

487



488

489

490

491

492



493

494

495

496

497

498


499


500

501

502

503

504

505

506

507

508

509

510

511

512



513

514

515

516

517

518

519

520

521

522

523


524


525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556

557

558

559

560

561

562

563

564

565

566

567

568

569

570

571

572

573

574

575

576

577

578

579

580

581

582

583

584

585

586

587

588

589

590

591

592

593

594

595

596

597

598

599

600

601

602

603

604

605

606

607

608

609

610

611

612

613

614

615

616

617

618

619

620

621

622

623

624

625

626

627

628

629

630

631

632

633

634

635

636

三、示例
1.启动时的UI界面
2.后台工作方法(费用方法)运行后,任务状态为Running
3.强制中止工作方法,运行任务状态Aborted
4.工作方法突发错误时,任务状态ThrowErrorStoped
5.工作方法正常结束或正常取消而结束时,任务状态Stopped
示例代码下载
posted on 2005-08-03 00:19 Net66 阅读(5867) 评论(27) 编辑 收藏 所属分类: C#
评论
2005-08-03 00:50
2005-08-03 01:50
218.81.148.* 2005-08-03 07:11
218.249.96.* 2005-08-03 08:46
222.43.70.* 2005-08-03 08:49
2005-08-03 08:54
222.47.87.* 2005-08-03 09:06
218.79.240.* 2005-08-03 09:08
2005-08-03 09:23
2005-08-03 09:39
2005-08-03 09:41
2005-08-03 18:48
2005-09-12 18:34
太好了 还有源码,可以少走一些弯路了
谢谢!
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实现的,原理和你的差不多,只不过客户端代码可以非常简单而已。
218.81.143.* 2005-09-14 20:59
我想你的解决方案一定相当不错,能否Mail一份,学习探讨探讨.the8341 at gmail.com
2005-09-19 11:19
呵呵,OK,这两天我整理一下也写篇文章和你分享。
218.79.244.* 2005-09-19 11:36
:-) 好文共享,期待中
2005-09-19 17:35
[楼主] 2005-09-20 09:10
222.82.56.* 2006-10-07 16:37
58.241.234.* 2007-05-04 15:07
2007-07-19 13:33
2008-01-10 10:56
2008-03-21 21:45
222.20.100.* 2008-08-19 17:54