【原创】Delphi中Thread Error解决三例

来源:互联网 发布:我的世界java安装 编辑:程序博客网 时间:2024/04/30 10:56

======================================================
注:本文源代码点此下载
======================================================

在实际工作中遇到的多线程故障三例,虽然一切都过去,也记录下来,权当做个总结。

一个delphi写的较老的多线程处理应用程序,数年间一直运行良好。近日突然频繁报线程错误,并且再两台不同的服务器中的错误情况也不相同,自然解决方法也不相同。

服务器1:

os:windows server 2003 x86 enterprise

错误表现:thread error:接收人拒绝此信号。(156)

解决过程:

使尽解数不得其门,我这个delphi菜鸟只好向高手求助,此时“鱼鱼桌面”的罗唐大伸援手,助我度过此难,在此向他表示感谢!

鱼鱼给的解决方案:

1. 单击开始,然后单击运行。

2. 键入 regedit,然后单击确定。

3. 导航到以下项:

hkey_local_machine\system\currentcontrolset\services\lanmanserver\parameters

4. 在右窗格中双击 irpstacksize 值。

注意:如果 irpstacksize 值仍不存在,请使用以下过程创建此值:

a. 在注册表的 parameters 文件夹中,右健单击右窗格。

b. 指向新建,然后单击 dword 值。

c. 键入 irpstacksize。

重要说明:因为此数值名称区分大小写,所以请完全按照其显示的形式键入“irpstacksize”。

5. 将“基数”更改为十进制。

6. 在“数值数据”框中,键入比列出的值大的一个值。

如果使用步骤 4 中描述的步骤创建了 irpstacksize 值,则默认值为 15。建议将此值增大 3,因此,如果以前的值为 11,则请键入 14,然后单击“确定”。

7. 关闭注册表编辑器。

8. 重新启动计算机。

处理结果:问题解决。

上述解决方案中提到的相关技术问题:

irpstacksize 可指定 windows 2000 server 所使用的 i/o 请求数据包 (irp) 中的堆栈位置的数目。对于某些传输、mac 驱动程序或文件系统驱动程序,您可能必须增加此数目。每个堆栈为各个接收缓冲区使用 36 字节的内存。此值在以下注册表位置设置:

hkey_local_machine\system\currentcontrolset\services\lanmanserver\parameters

在 windows 2000 中,irpstacksize 的默认值是 15,范围是从 11 到 50。

警告:注册表编辑器使用不当可导致严重问题,可能需要重新安装操作系统。microsoft 不能保证可以解决因注册表使用不当所导致的问题。使用注册表编辑器需要您自担风险。

如果该项不存在,可以使用注册表编辑器添加它。为此,请按照下列步骤操作:

单击“开始”,然后单击“运行”。

在“打开”框中,键入 regedit,然后单击“确定”。

展开以下注册表项:

hkey_local_machine\system\currentcontrolset\services\lanmanserver\parameters

单击“编辑”,指向“新建”,然后单击“dword 值”。

键入 irpstacksize,然后按 enter 键以命名该值。

单击“编辑”,然后单击“修改”。

在“数据值”框中,键入适用于您的网络的十六进制值(范围为从 0xb 到 0x32),然后单击“确定”。

服务器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对象。有哪些方式呢?单线程和多线程。

coinitialize指明以单线程方式创建。coinitializeex可以指定coinit_multithreaded以多线程方式创建。

创建单线程方式的com服务器时不用考虑串行化问题,多线程com服务器就要考虑。

在使用中,使用coinitialize创建可使对象直接与线程连接,得到最高的性能。创建多线程对象可以直接接收所有线程的调用,不必像单线程那样需要消息排队,但却需要com创建线程间汇集代理,这样访问效率不高。


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
原创粉丝点击