Delphi 如何解决在DLL的入口函数中创建或结束线程时卡死
先看一下使用Delphi开发DLL时如何使用MAIN函数,
通常情况下并不会使用到DLL的MAIN函数,因为delphi的框架已经把Main函数隐藏起来
而工程函数的 begin end 默认就是MAIN函数的DLL_PROCESS_ATTACH事件的处理代码,如需要完整的处理其他事件,
如 DLL_PROCESS_DETACH,DLL_THREAD_ATTACH, DLL_THREAD_DETACH,可在工程文件中做如下处理:
procedure DLLEntryPoint(Reason:DWord); begincase Reason ofDLL_PROCESS_ATTACH:StartMyThreadsAndWaitBegin(); // 创建并等待线程开始,这样会导致卡死 DLL_PROCESS_DETACH: StopMyThreadsAndWaitEnd(); // 停止并等待线程结束(或直接结束进程),这样会导致卡死 DLL_THREAD_ATTACH:; DLL_THREAD_DETACH:;end; end;beginDllProc := @DLLEntryPoint;DLLEntryPoint(DLL_PROCESS_ATTACH); end.
其中 DllProc 是SysInit中的全局变量,可简单理解为保存DLL Entry Point入口函数的地址(实际上RTL内部还有InitLib 和StartLib函数,由编译器自动处理)。
以上都是题外话,本文主要说明在DLL入口函数里面创建和退出线程为什么卡死和如何解决的问题。
1)在 DLL_PROCESS_ATTACH 事件中 创建线程 出现卡死的问题
通常情况下在这事件中仅仅是创建并唤醒线程,是不会卡死的,但如果同时有等待线程正式执行的代码,则会卡死,因为在该事件中,任何启动的线程都会由于LdrLoadDll中的LdrpLoaderLock 进入锁定状态而处于等待,无法进入线程函数,所以也就永远无法检测到正式执行的机会。
LdrpLoaderLock是系统的PE Loader的一个重要锁,保证系统资源的安全,而DLL 入口函数是在PE Loader 结束前执行的,LdrInitializeThunk等函数处理PE 映像 到内存中的过程中,LdrpLoaderLock是处于锁定状态的。
所以解决办法就是 在 DLL_PROCESS_ATTACH 事件中,仅创建并唤醒线程即可(此时即使是唤醒了,线程也是处理等待状态),线程函数会在DLL_PROCESS_ATTACH事件结束后才正式执行(实际上如果是通过LoadLibrary加载DLL,则会在LoadLibrary结束前后的某一时刻正式执行)。
2)在DLL_PROCESS_DETACH中结束线程出现卡死的问题
同样的原因,该事件是调用LdrUnloadDll中执行的,LdrpLoaderLock仍然是锁定状态的,而结束线程最终会调用LdrShutdownThread,均会释放PE Loader所维护的系统内部的共同资源(包括PEB 和TEB等模块信息和线程TLS数据等),此类共同资源刚好都是使用LdrpLoaderLock进行同步,所以在DLL_PROCESS_DETACH中调用ExitThread->LdrShutdownThread,必然导致卡死。
另外有一个特殊的现象,就是DLL_PROCESS_DETACH事件中,线程处于挂起状态,这是因为系统分配线程执行时间片的过程中由于PE Loader有资源处于锁定而导致线程无法进行下一个时间片,最终表现为线程函数处于假死状态,此状态基本上等同于线程的挂起(suspend)状态。
解决办法同样是避免在 DLL_PROCESS_DETACH事件中结束线程,那么我们可以在该事件中,创建并唤醒另外一个线程,在该新的线程里,结束需要结束的线程,并在完成后结束自身即可。唯一需要注意的是,一旦DLL_PROCESS_DETACH结束,内存中与DLL相关的PE映像资源可能会被释放掉,所以在后续的操作中尽量不要再对原来的数据进行操作,否则容易导致内存溢出(但其实释放与否是由内核决定的,也许将来经过某一个版本的补丁后,相关资源仍然会保留在内存可以使用)。
提醒: 标准的做法还是建议遵循MS的规则,不要在DLL入口函数中做线程相关的创建和释放操作。
总体上代码如下:
procedure DLLEntryPoint(Reason:DWord); begincase Reason ofDLL_PROCESS_ATTACH:TThread.CreateAnonymousThread(procedure beginStartMyThreadsAndWaitBegin();end).Start;DLL_PROCESS_DETACH:TThread.CreateAnonymousThread(procedure beginStopMyThreadsAndWaitEnd();end).Start;DLL_THREAD_ATTACH:; DLL_THREAD_DETACH:;end; end;beginDllProc := @DLLEntryPoint;DLLEntryPoint(DLL_PROCESS_ATTACH); end.
注: 此问题是属于系统多线程处理的问题,或者说是属于Windows API的使用方法问题,使用其他VB VC等开发的人员也可以参考此解决方法。
转载于:https://www.cnblogs.com/caibirdy1985/p/5790309.html
Delphi 如何解决在DLL的入口函数中创建或结束线程时卡死相关推荐
- mysql函数临时表_MySQL函数中创建临时表
我们都知道,在MySQL创建函数的时候,是不能返回table类型的数据的. 我有几个疑问: 1.在function中我首先创建一个临时表: create temporary table table_t ...
- windows DLL的入口函数DllMain【学习笔记】
文档有详细介绍 入口函数可能会被调用多次 实例代码1:判断两种情况 实例代码2:判断三种情况 实例代码3:判断四种情况 exe的Mian与Dll的DllMain 入口函数的区别 1.MIan只执行一次 ...
- C#利用lambda在函数中创建内部函数
有使用过JS的朋友,相信都知道function.JS中的function是可以在里面在定义一个作为内部使用的.有时为了控制作用域,或者这种小函数只在这个函数体内会使用,所以就不希望在外部在作额外的定义 ...
- java 通常在函数内部创建对象还是在外部创建对象_java中为什么在主函数中创建外部类对象可以,创建内部类对象就失败了呢?2类不都是非静态的吗?...
展开全部 public class OuterClass { public static void main(String[] args) { OuterClass outerClass = new ...
- php 变量传给另外一个函数,将在一个函数中创建的PHP变量传递给另一个
您可以将变量设为全局变量: function add_custom_price( $cart_object ) { global $newVar; foreach ( $cart_object-> ...
- 解决Java程序在Linux系统中创建文件或者文件夹后权限不足的问题
Tomcat 需要 8 以及以上 我在Java程序里面有很多生成文件的功能,比如用户上传文件.将数据生成xml文本等.我发现生成的文件权限全是:-rw-r-,而文件的拥有者是 root,这样就只有ro ...
- linux驱动入口函数执行了,probe函数没有执行排查
写了个spi1的驱动函数,insmod后发现没有反应. 添加打印信息后,发现执行了驱动入口函数(在入口函数中执行了spi_register_driver),但是probe函数没有执行,检查compat ...
- jQuery的入口函数
文档就绪事件 是指页面上的所有DOM元素,都加载完成 jQuery入口函数 为了防止文档在完全加载之前,运行jQuery代码 将jQuery放在入口函数中 即在DOM加载完成之后,才可以对DOM进行操 ...
- jQuery写法 入口函数
问答解疑 Q:什么是入口函? A:代码刷新完整个页面后,在执行. Q:为什么要用入口函数? A:因为在页面代码没有加载完时,jq代码在执行时可能掉用不到部分的内容(没有加载的内容),所以要用入口函数. ...
最新文章
- 前端有啥好用的手机模拟软件吗_隐藏应用,软件双开,一个APP就解决了
- 使用 Spring Boot 快速构建 Spring 框架应用
- Faster RCNN 训练自己的检测模型
- 它成为全球最受关注度的行业之一,连续5年都提到它
- 位图像素的颜色 携程编程大赛hdu
- leetcode1047. 删除字符串中的所有相邻重复项(栈的日常应用)
- 关于nginx keep-alive 参数的验证和心得
- python语言字符串_python中字符串的常见操作方法
- Educational Round 26 C. Two Seals
- php网站留言,php实现网站留言板功能
- 仿微信在线聊天源码 DuckChat聊天系统PHP采用 PHP 编写的聊天软件,简直就是一个完整的迷你版微信
- 用JavaScript写一个鼠标悬停变色事件
- 网优测试软件苹果手机,手机端网优测试软件详细介绍
- 英雄联盟服务器维修中启动游戏失败,电脑登录英雄联盟失败的八种解决方法
- 苹果台式电脑怎么使用计算机,苹果台式电脑开开不了机怎么办
- 恭喜腾佑当选“河南省企业上云推进联盟”理事单位!
- 菜鸟学MAC - mac十大使用技巧
- iOS 15 TableView刷新组头适配问题
- 关于pd.read_csv() 读数据的注意事项
- mactex+vscode+skim打造latex编译环境