多线程编程的探索与实践(图)
来源:互联网 发布:91助手mac版官方下载 编辑:程序博客网 时间:2024/05/16 05:31
在程序开发中,多线程是比较普遍的应用。还记得刚从事程序开发时,多线程对我来说是很神秘和充满向往的,如同雾里看花不知其要领和实质。由于工作中所参与的这个项目是基于多线程和多用户的,在经过一番历炼后对多线程有了一些拙见,特记录下来。
项目中没有直接使用开发环境所提供的多线程类库,而自己封装这些功能以提供更灵活便捷的编程方法。这里面基于一些概念:
任务巢:多个任务的集合,提供任务包先进先出的队列管理。
任务包:具体执行某个特定操作的任务,封装了要执行操作所需的若干参数、回调函数等。
投递:打好任务包后,将任务包传递到任务巢排队执行。
同步调用:调用及被调用者在同一个线程执行,在同一时刻只能执行其一。异步调用则反之。
在看一下投递任务包及进行异步操作是怎样实现的:
步骤: 创建任务包-->封装参数-->投递任务-->启动异步操作-->执行回调函数,发回执行结果。
上述的机制可用下图来描述:
具体实现代码如下:
(代码段1)
IInvokePackage ip = (IInvokePackage)SendSysMsg(new CMsg(MTSystemService.CreateInvokePackage, false)); //创建任务包
if (null != ip) {
ip.TargetObject = this;
ip.TargetMethod = new InvokePackageHandler1(SureLoadProp); //启动异步后要执行的操作
Debug.Assert(null != ip.TargetMethod);
ip.Parameters.Add(obj); //封装参数
ip.Parameters.Add(strPropName);
ip.UserState = obj;
ip.Callback = new AsyncCallback(this.OnSureLoadPropCallback); //回调函数
IAsyncResult ar = (IAsyncResult)SendSysMsg(new CMsg(MTSystemService.BeginInvoke, ip, this.m_PlugInMgr.DBJobNest)); //投递任务包,触发异步调用
上述操作就是实现异步操作的整个过程,最后任务包对象ip将被投递到任务巢按先进先出的原则排队执行,最终将会在另一个线程中执行函数SureLoadProp,执行完毕,回调函数this.OnSureLoadPropCallback将会被调用:
(代码段2)
private void OnSureLoadPropCallback(IAsyncResult ar){
ArrayList al = new ArrayList(1);
object Result = SendSysMsg(new CMsg(MTSystemService.EndInvoke,ar,al));//请求执行结果
IInvokePackage ip = (IInvokePackage)al[0];
bool bRet = false;
if(Result is Exception){
AppGlobal.g.LogError((Exception)Result);
bRet = false;
}
else{
bRet = Result is ArrayList;
}
PostSysMsg(new CMsg(MTAppPatientMgrPlugIn.QueryPatientsResult, Result, ar, bRet));//发回操作结果
}
在上述函数中,首先通过消息向系统请求指定异步操作的执行结果,此时如果该任务还未执行完,此处将会等待直至执行完。然后通过消息QueryPatientsResult将执行结果Result对象返回给调用者。
再回头看一下这里面的机制:
代码段1的操作是在当前线程中(比如主线程)执行的,当任务包投递出去后就不用管了,当前线程可继续进行接下来的操作,直到接受任务包的任务巢(已经是另外一个线程)执行完毕通知回来再获取操作结果。这样做的好处就是,当要执行时间过长消耗性能较大的操作时,如果不用另外的线程来做,那么当前线程就要等待这个操作的完成,才能执行其他操作,这时就会出现某些持续的操作停顿,用户的操作也要受到影响。那么此时,将该任务交给另一个线程来做,当前线程的其他的操作不受影响,用户的操作也会很流畅。
当任务包投递出去后,并不能保证马上执行,因为接受此任务包的任务巢可能有多个任务包,它们是逐一执行的,刚投递的任务只有等待其他任务包执行完成后才能执行。虽然这样能确保在此任务巢中的任务能同步执行,但与其他任务巢(线程中的操作)不能同步,所以如果它们要访问同一资源时,就可能会出现读写迸发操作,造成数据不一致。这时可用锁定机制,这方面的应用在以前的文章中叙述过。
那么如何将任务包投递到特定的任务巢呢,看代码1中的最后一句代码:
IAsyncResult ar = (IAsyncResult)SendSysMsg(new CMsg(MTSystemService.BeginInvoke, ip, this.m_PlugInMgr.DBJobNest));此时投递任务包是指定了任务巢this.m_PlugInMgr.DBJobNest,此任务巢是专门用作数据库操作的。如不指定,将会被投递到默认任务巢。
总结:
1. 在主线程中启动异步操作后,根据需要可在异步线程里面再次下一层异步操作。虽然异步操作增加程序执行的效率,但同时会增加程序的复杂度和管理难度。所以异步操作不是越多层次越好,在最大性能的前提下应尽量减少异步调度嵌套次数。
2. 由于线程的调度几乎是在无声无息地进行,一旦出现多线程的问题将很难较直观地发现问题,此时必须要很清楚线程调度的思路,并在关键的地方输出如线程ID等信息,程序中隐晦的问题才会逐渐明朗,这是解决多线程问题的关键步骤。
- 多线程编程的探索与实践(图)
- Ruby 多线程探索实践与归纳总结 夏洛克
- 《编程的奥秘》本人按 第四章实践与探索的要求 写的代码
- “软件工程”课程教学改革的探索与实践
- C#:多线程编程探索
- 多线程编程探索
- 浅析C++多线程编程理论与实践
- 浅析C++多线程编程理论与实践
- Java5 多线程与TCP编程实践
- 美图HTTPS优化探索与实践
- MYSQL集群探索与实践
- mysql集群探索与实践
- Pandas数据探索与实践
- Android 模块化探索与实践
- HTTPS优化探索与实践
- C#多线程编程实践
- 基于IaaS的即时通讯PaaS平台构建探索与实践
- JVM深入探索与实践,谈谈我的理解
- 网页框架
- 空间数据库引擎探究
- compareDate
- 用subversion(SVN)进行版本管理 (二)
- 一个小工具,用来自动清除Outlook 的地址自动完成缓存 (Outlook e-mail address auto complete cache)
- 多线程编程的探索与实践(图)
- 用subversion(SVN)进行版本管理 (三)
- [ASP.NET2.0]如何利用 DataReader 实现分页
- Groovyb脚本速成教程
- 基于Mapserver的WebGIS设计
- 开源WebGIS-Mapserver在windows下的安装
- 开博了,大家支持一下
- web.config常用方法
- 地物波谱反射率与遥感影像成像相仿关系浅究