【转】衔接UI线程和管理后台工作线程的类(多线程、异步调用)
2008-09-26 00:32
435 查看
衔接UI线程和管理后台工作线程的类(多线程、异步调用)
转:/article/6213742.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 )方便调用。在实际使用时,可在继承类中定义多个相同调用接口的方法,避免重复编码,较为方便。
给大家作个参考,而大牛呢,多点指正。当是扔个砖头,想砸块玉吧。
二、代码
1using System;
2using System.Windows.Forms;
3
4namespace Net66.AsynchThread
5
523
三、示例
1.启动时的UI界面
2.后台工作方法(费用方法)运行后,任务状态为Running
3.强制中止工作方法,运行任务状态Aborted
4.工作方法突发错误时,任务状态ThrowErrorStoped
5.工作方法正常结束或正常取消而结束时,任务状态Stopped
示例代码下载
posted on 2005-08-03 00:19 Net66 阅读(5867) 评论(27) 编辑 收藏 所属分类: C#
#1楼 2005-08-03 00:50 idior
good. 多线程的文章比较少, 下次谈谈同步的问题吧.
回复 引用 查看
#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 [未注册用户]
System.Threading.ThreadPool还是不要用的好,这东西牵扯进程的异步调用,这东西微软就该设置成internal
回复 引用
#5楼 222.43.70.* 2005-08-03 08:49 学习 [未注册用户]
http://www.vckbase.com/document/viewdoc/?id=1126
回复 引用
#6楼 2005-08-03 08:54 James
这些BeginXXXX的方法都是使用了ThreadPool的。
回复 引用 查看
#7楼 222.47.87.* 2005-08-03 09:06 张老三 [未注册用户]
刚完成了一个图库管理系统, 使用的就是这种方式. 感觉还不错.
回复 引用
#8楼 218.79.240.* 2005-08-03 09:08 win [未注册用户]
文章的意思应该是不用显式使用ThreadPool,通过系统默认调用吧
回复 引用
#9楼 2005-08-03 09:23 BearTang
好文章。。
回复 引用 查看
#10楼 2005-08-03 09:39 妖居
异步委托也是刚刚用过,做一个分析目录的工具的时候用的。
回复 引用 查看
#11楼 2005-08-03 09:41 James
我的意思是说,这些异步委托调用什么的,其内部都是使用了ThreadPool的,这样当然不用你自己去直接使用ThreadPool了。
回复 引用 查看
#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 双鱼座
@net66:
呵呵,OK,这两天我整理一下也写篇文章和你分享。
回复 引用 查看
#17楼 218.79.244.* 2005-09-19 11:36 net66
@双鱼座
:-) 好文共享,期待中
回复 引用 查看
#18楼 2005-09-19 17:35 双鱼座
我的文章已经写完:http://Barton131420.cnblogs.com/articles/239855.html
回复 引用 查看
#19楼 [楼主] 2005-09-20 09:10 Net66
双鱼座的文章,作者功底颇深.
http://www.cnblogs.com/Barton131420/articles/239855.html
回复 引用 查看
#20楼 222.82.56.* 2006-10-07 16:37 可乐[匿名] [未注册用户]
看了例程非常激动,也许是还有很多东西要学没有看的很彻底,希望楼主能解释,就是在UI中启动一个辅助线程后往往会应为需要在UI启动的这个辅助线程中在启动其他线程,这个时候该怎样使用Task抽象类,该如何将辅助线程启动的其他线程中的信息显示在UI中,还有怎么才能利用AsynchThread 在UI中停止辅助线程的时候能同时停止辅助线程启动的其他线程,希望楼主能解答,谢谢!!
回复 引用
#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 娄玲 [未注册用户]
下了,研究研究,谢谢啦。
回复 引用
td { font-size: 12px }
.commentTextBox
{
font-family : Verdana;
font-size: 13px;
}
a.blue:visited,
a.blue:active,
a.blue:link,
a.blue:hover
{
color:blue;
}
.userData { BEHAVIOR: url(#default#userdata) }
转:/article/6213742.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 )方便调用。在实际使用时,可在继承类中定义多个相同调用接口的方法,避免重复编码,较为方便。
给大家作个参考,而大牛呢,多点指正。当是扔个砖头,想砸块玉吧。
二、代码
1using System;
2using System.Windows.Forms;
3
4namespace Net66.AsynchThread
5
523
三、示例
1.启动时的UI界面
2.后台工作方法(费用方法)运行后,任务状态为Running
3.强制中止工作方法,运行任务状态Aborted
4.工作方法突发错误时,任务状态ThrowErrorStoped
5.工作方法正常结束或正常取消而结束时,任务状态Stopped
示例代码下载
posted on 2005-08-03 00:19 Net66 阅读(5867) 评论(27) 编辑 收藏 所属分类: C#
评论
#1楼 2005-08-03 00:50 idior
good. 多线程的文章比较少, 下次谈谈同步的问题吧.回复 引用 查看
#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 [未注册用户]
System.Threading.ThreadPool还是不要用的好,这东西牵扯进程的异步调用,这东西微软就该设置成internal回复 引用
#5楼 222.43.70.* 2005-08-03 08:49 学习 [未注册用户]
http://www.vckbase.com/document/viewdoc/?id=1126回复 引用
#6楼 2005-08-03 08:54 James
这些BeginXXXX的方法都是使用了ThreadPool的。回复 引用 查看
#7楼 222.47.87.* 2005-08-03 09:06 张老三 [未注册用户]
刚完成了一个图库管理系统, 使用的就是这种方式. 感觉还不错.回复 引用
#8楼 218.79.240.* 2005-08-03 09:08 win [未注册用户]
文章的意思应该是不用显式使用ThreadPool,通过系统默认调用吧回复 引用
#9楼 2005-08-03 09:23 BearTang
好文章。。回复 引用 查看
#10楼 2005-08-03 09:39 妖居
异步委托也是刚刚用过,做一个分析目录的工具的时候用的。回复 引用 查看
#11楼 2005-08-03 09:41 James
我的意思是说,这些异步委托调用什么的,其内部都是使用了ThreadPool的,这样当然不用你自己去直接使用ThreadPool了。回复 引用 查看
#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 双鱼座
@net66:呵呵,OK,这两天我整理一下也写篇文章和你分享。
回复 引用 查看
#17楼 218.79.244.* 2005-09-19 11:36 net66
@双鱼座:-) 好文共享,期待中
回复 引用 查看
#18楼 2005-09-19 17:35 双鱼座
我的文章已经写完:http://Barton131420.cnblogs.com/articles/239855.html回复 引用 查看
#19楼 [楼主] 2005-09-20 09:10 Net66
双鱼座的文章,作者功底颇深.http://www.cnblogs.com/Barton131420/articles/239855.html
回复 引用 查看
#20楼 222.82.56.* 2006-10-07 16:37 可乐[匿名] [未注册用户]
看了例程非常激动,也许是还有很多东西要学没有看的很彻底,希望楼主能解释,就是在UI中启动一个辅助线程后往往会应为需要在UI启动的这个辅助线程中在启动其他线程,这个时候该怎样使用Task抽象类,该如何将辅助线程启动的其他线程中的信息显示在UI中,还有怎么才能利用AsynchThread 在UI中停止辅助线程的时候能同时停止辅助线程启动的其他线程,希望楼主能解答,谢谢!!回复 引用
#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 娄玲 [未注册用户]
下了,研究研究,谢谢啦。回复 引用
td { font-size: 12px }
.commentTextBox
{
font-family : Verdana;
font-size: 13px;
}
a.blue:visited,
a.blue:active,
a.blue:link,
a.blue:hover
{
color:blue;
}
.userData { BEHAVIOR: url(#default#userdata) }
相关文章推荐
- 【转】衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用) .
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)[转]
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用) .
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- 衔接UI线程和管理后台工作线程的类(多线程、异步调用)
- C#多线程 定时重复调用异步线程即System.Threading.Timer类使用小例
- ui线程和后台线程异步
- C#构建多线程应用程序(1) —— 使用委托来自动创建次线程以实现异步方法的调用
- Java【多线程知识总结(2)】调用setDaemon(true)变成后台线程
- Java【多线程知识总结(2)】调用setDaemon(true)变成后台线程
- Java【多线程知识总结(2)】调用setDaemon(true)变成后台线程