在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
在实际工作中遇到的多线程故障三例,虽然一切都过去,也记录下来,权当做个总结。
一个Delphi写的较老的多线程处理应用程序,数年间一直运行良好。近日突然频繁报线程错误,并且再两台不同的服务器中的错误情况也不相同,自然解决方法也不相同。
服务器1: OS:Windows Server 2003 x86 Enterprise 错误表现:Thread Error:接收人拒绝此信号。(156) 解决过程: 使尽解数不得其门,我这个Delphi菜鸟只好向高手求助,此时“鱼鱼桌面”的罗唐大伸援手,助我度过此难,在此向他表示感谢!
鱼鱼给的解决方案: 1. 单击开始,然后单击运行。 注意:如果 IRPStackSize 值仍不存在,请使用以下过程创建此值: a. 在注册表的 Parameters 文件夹中,右健单击右窗格。 重要说明:因为此数值名称区分大小写,所以请完全按照其显示的形式键入“IRPStackSize”。 5. 将“基数”更改为十进制。 如果使用步骤 4 中描述的步骤创建了 IRPStackSize 值,则默认值为 15。建议将此值增大 3,因此,如果以前的值为 11,则请键入 14,然后单击“确定”。
处理结果:问题解决。
上述解决方案中提到的相关技术问题: IRPStackSize 可指定 Windows 2000 Server 所使用的 I/O 请求数据包 (IRP) 中的堆栈位置的数目。对于某些传输、MAC 驱动程序或文件系统驱动程序,您可能必须增加此数目。每个堆栈为各个接收缓冲区使用 36 字节的内存。此值在以下注册表位置设置: 警告:注册表编辑器使用不当可导致严重问题,可能需要重新安装操作系统。Microsoft 不能保证可以解决因注册表使用不当所导致的问题。使用注册表编辑器需要您自担风险。
服务器2: OS:Windows Server 2003 R2 x86 Enterprise 错误表现: 工作子线程为单一循环线程,一段时间(几天)后线程停止工作,程序不报错,通过主界面线程对工作线程执行Suspend后程序抛出异常
1.Thread Error: 句柄无效。 (6) 解决过程:经过多方查找资料得知该问题简单的解决办法 解决方案: 原因是当初对相关线程的FreeOnTerminate属性指定为True,当线程不能继续执行工作后过后系统对线程释放,故返回该错误。 FreeOnTerminate属性改为为False,在需要线程释放的地方用Free的方法显式的释放线程即可。 处理结果:不再该出现该异常,但问题仍未得到解决,仍抛出异常,但异常已变为:
2.Thread Error: 拒绝访问。 (5) 解决过程:经过多方查找资料未能解决该问题,最后通过调试跟踪解决 解决方案: 通过网上资料得出引发该问题原因一般有两点: 1.未使用线程同步; 2.未使用CoInitialize对线程中调用的COM组件初始化套间; 实际情况是: 1.该程序的工作线程中已用Synchronize()与主线程做了同步,但问题依旧; 2.在线程的Execute方法中用了CoInitialize(nil)为Com组件初始了套间,并在线程结束处调用了CoUninitialize释放,问题得不到解决;
服务器调试过程中发现工作线程抛出另一个异常,是在每次循环过程中,写入Log日志文件时无法独占式访问所引发的;由于日志是文本文件并且不会有其他线程、进程访问,故将该独占式访问改为共享访问即可。
处理结果:问题解决。
事后思考:该故障表现无规律可循,并不是线程中每次循环均会引发此错误,而是不知程序执行多久后、不确定线程循环了数千次后出现此问题...至今对此稳定的老Delphi程序突发如此怪病慎感蹊跷...个人推测应该是更换新服务器后系统处理能力更加高效,而硬盘写入成为了瓶颈,导致文件访问未能在下次轮询前关闭,引发了IO冲突所致,以上纯属个人猜测,若有高手对此有更深入认识,欢迎留言解惑^_^
上述解决方案中提到的相关技术问题:
CoInitialize CoInitialize是 Windows提供的API函数,用来告诉 Windows以单线程的方式创建com对象。应用程序调用com库函数(除CoGetMalloc和内存分配函数)之前必须初始化com库。 返回值S_OK : 该线程中COM库初始化成功S_FALSE 该线程中COM库已经被初始化 CoInitialize () 标明以单线程方式创建。 使用 CoInitialize 创建可以使对象直接与线程连接,得到最高的性能。 CoInitialize并不装载COM 库,它只用来初始化当前线程使用什么样的套间。使用这个函数后,线程就和一个套间建立了对应关系。线程的套间模式决定了该线程如何调用COM对象,是否需要列集等。 CoInitialize ()并不会干扰客户和服务器之间的通信,它所做的事情是让线程注册一个套间,而线程运行过程中必然在此套间。CoInitialize和CoUninitialize必须成对使用。
有关单线程或多线程中的COM库初始化 CoInitialize、CoInitializeEx都是windows的API,主要是告诉windows以什么方式为程序创建COM对象。有哪些方式呢?单线程和多线程。 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论