一种基于运行期动态跟踪的函数执行超时与死锁检测方法.pdf

上传人:r7 文档编号:1639130 上传时间:2018-06-30 格式:PDF 页数:22 大小:1.69MB
返回 下载 相关 举报
摘要
申请专利号:

CN201510118723.6

申请日:

2015.03.18

公开号:

CN104636259A

公开日:

2015.05.20

当前法律状态:

实审

有效性:

审中

法律详情:

实质审查的生效IPC(主分类):G06F 11/36申请日:20150318|||公开

IPC分类号:

G06F11/36

主分类号:

G06F11/36

申请人:

厦门雅迅网络股份有限公司

发明人:

时宜; 王国清; 夏欢; 江永聪

地址:

361000福建省厦门市软件园二期观日路46号

优先权:

专利代理机构:

厦门市精诚新创知识产权代理有限公司35218

代理人:

巫丽青

PDF下载: PDF下载
内容摘要

本发明涉及计算机技术领域,一种基于运行期动态跟踪的函数执行超时与死锁检测的方法包括A、在待检测函数的运行入口插入一段跟踪代码,区分待检测函数当前运行所属线程,登记各个进入运行的待检测函数的特征信息,并返回此特征信息对象的引用数据给待测函数临时保存。B、在待测函数的运行出口也插入对应的跟踪代码,根据A中曾返回的特征信息对象的访问信息,将函数特征信息对象从当前运行所属线程的数据结构中取消登记。C、在进程中创建一独立监视线程,对于时间计数超过第一级时间计数阈值的待测函数,则表示其运行时间偏长,即超时,而对于时间计数超过第二级时间计数阈值的待测函数,则表示其运行时间过长,存在死锁可能。本发明能有效判断超时和死锁。

权利要求书

权利要求书
1.  一种基于运行期动态跟踪的函数执行超时与死锁检测方法,其特征在于:该 方法主要包括三个部分:
A、在待检测函数的运行入口插入一段跟踪代码,区分待检测函数当前运行 所属线程,分别为不同的线程建立相应的数据结构,登记各个进入运行的待检 测函数的特征信息,并返回此特征信息对象的引用数据给待测函数临时保存。 对于存在嵌套调用关系的待测函数,则按进入运行的先后次序创建一个链表数 据结构对多个待检测函数特征信息进行保存,
B、在待测函数的运行出口插入对应的跟踪代码,根据A中曾返回的特征信 息对象的访问信息,将函数特征信息对象从当前运行所属线程的数据结构中取 消登记;
C、在进程中创建一独立监视线程,以一个单位时间周期内扫描各个线程中 由于一个或多个待测函数进入运行产生的特征信息对象,并对其进行时间计数 递增,对于时间计数超过第一级时间计数阈值的待测函数,则表示其运行时间 偏长,即超时,而对于时间计数超过第二级时间计数阈值的待测函数,则表示 其运行时间过长,存在死锁可能。

2.  根据权利要求1所述的一种基于运行期动态跟踪的函数执行超时与死锁检测 方法,其特征在于:封装一个可复用的函数调用跟踪组件,该函数调用跟踪 组件实现上述A、B、C三部分,其主要包括:为多个线程各自独立维护、跟 踪待测函数运行的数据结构,以及一个独立的监视线程,对应地,为应用此 发明的待检测程序提供函数调用跟踪组件包装对象、函数调用跟踪代理对象 来运用函数调用跟踪组件,
上述函数调用跟踪组件包装对象定义为,控制函数调用跟踪组件在待测 目标程序中进行加载、启动、调用、停止、释放活动的代理类对象,为待测 目标程序使用函数调用跟踪组件提供对象级别的管理;
上述函数调用跟踪代理对象定义为,接收函数调用信息,通过函数调用 跟踪组件的API接口将待测目标函数信息、进入和退出动作传递进函数调用 跟踪组件中以供超时或死锁判断的代理类对象;
函数调用跟踪组件中为多个线程独立维护、跟踪待测函数运行的数据结 构具体定义如下:
将所述待检测函数特征信息对象定义为“函数调用跟踪记录”,其记录 所跟踪目标程序模块中某个待测函数调用信息、并缓存在函数调用跟踪组件 中供监视线程检测超时或死锁的一个数据对象,其中主要记录了待测函数的 进入时间点、已进入运行后的滞留时间长度、所属的程序模块信息(如模块 名称)、特征信息;
定义线程内函数调用跟踪记录链为线程中多个嵌套进行的待测函数调 用所生成函数调用跟踪记录的一个链式数据结构,其中待测函数的函数调用 跟踪记录在链表中的先后顺序与待测函数嵌套调用的先后顺序相同;每个可 能运行到的线程均拥有一个线程内函数调用跟踪记录链;
函数调用跟踪组件包装对象和函数调用跟踪代理对象位于待测函数所 属之待跟踪程序模块中,函数调用跟踪记录由线程内函数调用跟踪记录链的 链式结构所管理,而线程内函数调用跟踪记录链对象又保存在函数调用跟踪 组件为待测目标程序进程的各线程创建的一个线程内函数调用跟踪记录链 对象集合中,
函数调用跟踪组件包装对象主要管理函数调用跟踪组件的加载、启动、 调用、停止、释放,主要通过操作系统API、及函数调用跟踪组件本身输出 的用户API对函数调用跟踪组件的运行进行控制管理,同时负责将函数调用 跟踪组件输出的用户API调用信息复制给函数调用跟踪代理对象进行静态化 保存;
函数调用跟踪代理对象则通过调用函数调用跟踪组件包装对象复制而 来的API函数指针,将待测函数进入、退出调用动作传递到函数调用跟踪组 件中,驱动函数调用跟踪组件查找当前线程对应的线程内函数调用跟踪记录 链对象,并在其中建立函数调用跟踪记录。

3.  根据权利要求2所述的一种基于运行期动态跟踪的函数执行超时与死锁检测 方法,其特征在于:函数调用跟踪组件加载初始化步骤如下:
Step11.待测目标程序模块在完成加载、初始化后,通过函数调用跟踪 组件包装对象加载函数调用跟踪组件,并驱动其进行初始化启动;
Step12.函数调用跟踪组件在初始化过程中首先创建一个“线程内函数 调用跟踪记录链对象的集合”对象;
Step13.函数调用跟踪组件在初始化过程的最后,创建一独立工作线程, 用于对运行了待测函数的各个线程所对应的线程内函数调用跟踪记录链对 象进行扫描检测。

4.  根据权利要求2所述的一种基于运行期动态跟踪的函数执行超时与死锁检测 方法,其特征在于:待测函数进入跟踪步骤如下:
Step21.待测函数进入运行后,创建“函数调用跟踪代理对象”;
Step22.“函数调用跟踪代理对象”创建时自动调用构造函数,并在其 中调用“函数调用跟踪组件”输出的记录待测函数进入动作的API函数,将 待测函数进入动作和待测函数信息一并传递到函数调用跟踪组件中;
Step23.函数调用跟踪组件通过系统API获取当前运行线程的id标识 符,并根据此id标示符,从“线程内函数调用跟踪记录链对象”的集合对 象中检索出对应的“线程内函数调用跟踪记录链对象”;
Step24.为当前待测函数生成新的函数调用跟踪记录对象,同时在其中 保存外部通过函数调用参数逐层传入的待测函数信息;
Step25.将新创建的函数调用跟踪记录对象,插入到对应的线程内函数 调用跟踪记录链的头部,作为当前线程的最近一次函数调用跟踪记录;
Step26.最终,将新创建的函数调用跟踪记录对象的持有信息逐层返回 给“函数调用跟踪代理对象”保存,留待待测函数退出时使用。

5.  根据权利要求2所述的一种基于运行期动态跟踪的函数执行超时与死锁检测 方法,其特征在于:待测函数退出跟踪步骤如下:
Step31.待测函数退出运行前,并无论在函数内部何处返回,“函数调用 跟踪代理对象”将被自动销毁,其析构函数自动发生调用,通过在其析构函 数内执行“函数调用跟踪组件”输出的记录待测函数退出动作的API函数, 将曾保存的函数调用跟踪记录对象的持有信息传递到函数调用跟踪组件中;
Step32.函数调用跟踪组件通过系统API获取当前运行线程的id标识 符,并根据此id标识符,从“线程内函数调用跟踪记录链对象”的集合对 象中检索出当前线程的“线程内函数调用跟踪记录链对象”;
Step33.验证当前线程内函数调用跟踪记录链的头部所保存函数调用跟 踪记录对象,与外部传入函数调用跟踪记录对象是否匹配、相同。若不一致, 则输出错误信息,直接转向Step35,否则继续;
Step34.移除“线程内函数调用跟踪记录链”头部引用的最近一次函数 调用跟踪记录;
Step35.结束。

6.  根据权利要求2所述的一种基于运行期动态跟踪的函数执行超时与死锁检测 方法,其特征在于:函数调用超时与死锁检测步骤如下:
Step41.将函数调用跟踪组件中所有的“线程内函数调用跟踪记录链对 象”(可使用多种数据结构实现集合对象)的引用信息(如对象地址)转存 为一个一维数组,以供遍历;
Step42.遍历该一维数组,设置当前数组访问下标为1,从第一个元素开 始;
Step43.判断当前数组访问下标,若超出数组长度,则转向Step49,否 则继续;
Step44.根据当前数组访问下标,取得一维数组中对应的“线程内函数 调用跟踪记录链对象”;
Step45.对“线程内函数调用跟踪记录链对象”的已运行时间进行计数 增加1,表示增加一个时间单位;
Step46.将“线程内函数调用跟踪记录链对象”的已运行时间与第一级时间 计数阈值进行大小判断,若超出,则输出函数运行超时日志信息进行提示;
Step47.将“线程内函数调用跟踪记录链对象”的已运行时间与第二级 时间计数阈值(死锁判断)进行大小判断,若超出,则输出函数运行死锁日 志信息进行提示;
Step48.当前数组访问下标自增1,返回Step43;
Step49.结束循环。

说明书

说明书一种基于运行期动态跟踪的函数执行超时与死锁检测方法
技术领域
本发明涉及计算机技术领域,具体涉及一种基于运行期动态跟踪的函数执 行超时与死锁检测的方法。
背景技术
所有计算机软件运行过程中,都会存在大量的函数调用,并且大部分函数 一般设计为可在一个足够小时间(纳秒、毫秒级)内运行完毕。而在实际的计 算机软件编制过程中,由于设计、开发上的缺陷或疏忽,有时函数运行可能发 生极为严重的故障,例如运行死锁。这相对于函数运行时发生异常(异常一般 可以被捕获)更加严重,因为此时软件将处于“呆滞”状态,已无法运行捕获 错误信息,对软件系统的集成联试、运行造成极大的困扰。同时这样的故障也 非常难于排查,因为在数万、数十万行代码中,在1秒成千上万个函数调用中 准确定位到故障函数是非常困难的,特别是当问题以随机小概率发生的时候。
为了排除此类故障,一般普通的作法是针对疑点函数调用,在函数进入和 退出的运行点进行日志打印跟踪输出,然后在发生函数调用死锁时,检查输出 的日志,检索最后一次进入但是却无退出记录的函数调用来进行判断。从理论 上而言该方法具备一定的可行性,但同时也存在很多困扰。首先,由于初始时 不确认是哪一函数调用存在问题,因此,可能存在疑虑需要日志跟踪的函数调 用有很多,在日志中检索时便存在大量正常函数的日志干扰,检索困难;其 二,由于多线程的存在,各函数调用进入、退出的日志记录可呈交错态,进一 步增加了判断有进入无退出的函数调用的困难;其三,高频度的函数调用将输 出大量的跟踪日志,极为影响性能,可能会破坏死锁发生的性能条件,从而不 能观测到死锁;其四,函数调用的退出和进入不同,可能存在多个分支退出 点,这在编码开发上也是不方便的。
发明内容
有鉴于此,本发明的主要目的在于提供一种基于运行期动态跟踪的函数执 行超时与死锁检测的方法及组件,能对C++编写的程序进行有效、方便的死锁 检测,以降低人工分析死锁的工作量,提高分析效率。
为了达到上述目的,本发明所采用的技术方案是如下实现的,一种基于运 行期动态跟踪的函数执行超时与死锁检测的方法,该方法主要包括三个部分:
A、在待检测函数的运行入口插入一段跟踪代码,区分待检测函数当前运 行所属线程,分别为不同的线程建立相应的数据结构,登记各个进入运行的待 检测函数的特征信息(如函数名、事先预分配的唯一标识符等),并返回此特 征信息对象的引用数据(对象地址)给待测函数临时保存。对于存在嵌套调用 关系的待测函数,则按进入运行的先后次序创建一个链表数据结构对多个待检 测函数特征信息进行保存。
B、类似A,在待测函数的运行出口(可能有多个运行退出点)也插入对应 的跟踪代码,根据A中曾返回的特征信息对象的访问信息,将函数特征信息对 象从当前运行所属线程的数据结构中取消登记。
C、在进程中创建一独立监视线程,以一个足够短的单位时间周期(推荐值 为1秒,避免对程序运行造成太多额外运行开销)内扫描各个线程中由于一个 或多个待测函数进入运行产生的特征信息对象,并对其进行时间计数递增,对 于时间计数超过第一级时间计数阈值(建议3秒以内,除非阻塞或高密度计算, 否则大部分编程良好的函数不需要运行超出1秒以上的时间)的待测函数,则 表示其运行时间偏长,即超时,而对于时间计数超过第二级时间计数阈值(足 够大值,建议30秒左右,以排除部分计算负担较重、耗时较久的函数影响)的 待测函数,则表示其运行时间过长,存在死锁可能。
为使上述技术方案的应用足够简便,本发明对其进行封装,封装为一个可 复用的函数调用跟踪组件(在Windows系统中以DLL体现)。
该函数调用跟踪组件将实现上述A、B、C三部分的主要有效实现,其中主 要包括:为多个线程各自独立维护、跟踪待测函数运行的数据结构,以及一个 独立的监视线程。
对应地,为应用此发明的待检测程序提供函数调用跟踪组件包装对象、函 数调用跟踪代理对象来运用函数调用跟踪组件。
上述函数调用跟踪组件包装对象定义为,控制函数调用跟踪组件在待测目 标程序中进行加载、启动、调用、停止、释放活动的代理类对象,为待测目标 程序使用函数调用跟踪组件提供对象级别的管理。
上述函数调用跟踪代理对象定义为,接收函数调用信息,通过函数调用跟 踪组件的API接口将待测目标函数信息、进入和退出动作传递进函数调用跟踪 组件中以供超时或死锁判断的代理类对象。
函数调用跟踪组件中为多个线程独立维护、跟踪待测函数运行的数据结构 具体定义如下。
将上述A部分中提到的待检测函数特征信息对象,正式约定为“函数调用 跟踪记录”,定义为记录所跟踪目标程序模块中某个待测函数调用信息、并缓 存在函数调用跟踪组件中供监视线程检测超时或死锁的一个数据对象,其中主 要记录了待测函数的进入时间点、已进入运行后的滞留时间长度、所属的程序 模块信息(如模块名称)、特征信息(如函数名称)。
待检测函数之间完全存在嵌套调用的可能性,即,一个待测函数func1进 入运行后、尚未退出前,另一个待测函数func2进入运行。对于此种情形,由 于当前线程中func1的函数调用跟踪记录尚未被删除,就会面临被func2的函 数跟踪记录覆写、从而丢失func1的函数调用跟踪记录的风险。为解决此问 题,定义线程内函数调用跟踪记录链为线程中多个嵌套进行的待测函数调用所 生成函数调用跟踪记录的一个链式数据结构,其中待测函数的函数调用跟踪记 录在链表中的先后顺序与待测函数嵌套调用的先后顺序相同。每个可能运行到 的线程均拥有一个线程内函数调用跟踪记录链。
上述各部件,函数调用跟踪组件包装对象和函数调用跟踪代理对象位于待 测函数所属之待跟踪程序模块中。函数调用跟踪记录由线程内函数调用跟踪记 录链对象的链式结构所管理,而线程内函数调用跟踪记录链对象又保存在函数 调用跟踪组件为待测目标程序进程的各线程创建的一个线程内函数调用跟踪记 录链对象集合中。
函数调用跟踪组件包装对象主要管理函数调用跟踪组件的加载、启动、调 用、停止、释放,主要通过操作系统API、及函数调用跟踪组件本身输出的用 户API对函数调用跟踪组件的运行进行控制管理,同时负责将函数调用跟踪组 件输出的用户API调用信息(如函数指针方式)复制给函数调用跟踪代理对象 进行静态化保存(静态化指保存数据不受单个函数调用跟踪代理对象创建和销 毁的影响)。
函数调用跟踪代理对象则通过调用函数调用跟踪组件包装对象复制而来的 API函数指针,将待测函数进入、退出调用动作传递到函数调用跟踪组件中, 驱动函数调用跟踪组件查找当前线程对应的线程内函数调用跟踪记录链对象, 并在其中建立函数调用跟踪记录。
进一步,函数调用跟踪组件加载初始化步骤如下:
Step11.待测目标程序模块在完成加载、初始化后,通过函数调用跟踪组件包 装对象加载函数调用跟踪组件,并驱动其进行初始化启动。
Step12.函数调用跟踪组件在初始化过程中首先创建一个“线程内函数调用跟 踪记录链对象的集合”数据结构。
Step13.函数调用跟踪组件在初始化过程的最后,创建一独立工作线程,用于 对运行了待测函数的各个线程所对应的线程内函数调用跟踪记录链对象进行扫 描检测。
进一步,待测函数进入跟踪步骤如下:
Step21.待测函数进入运行后,创建“函数调用跟踪代理对象”。
Step22.“函数调用跟踪代理对象”创建时自动调用构造函数,并在其中调用 “函数调用跟踪组件”输出的记录待测函数进入动作的API函数,将待测函数 进入动作和待测函数信息一并传递到函数调用跟踪组件中。
Step23.函数调用跟踪组件通过系统API获取当前运行线程的id标识符,并根 据此id标示符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出对 应的“线程内函数调用跟踪记录链对象”。
Step24.为当前待测函数生成新的函数调用跟踪记录对象,同时在其中保存外 部通过函数调用参数逐层传入的待测函数信息。
Step25.将新创建的函数调用跟踪记录对象,插入到对应的线程内函数调用跟 踪记录链的头部,作为当前线程的最近一次函数调用跟踪记录。
Step26.最终,将新创建的函数调用跟踪记录对象的持有信息(如对象地址)逐 层返回给“函数调用跟踪代理对象”保存,留待待测函数退出时使用。
进一步,待测函数退出跟踪步骤如下:
Step31.待测函数退出运行前,并无论在函数内部何处返回,受益于编程语言提 供的特性,“函数调用跟踪代理对象”将被自动销毁,其析构函数自动发生调 用,通过在其析构函数内执行“函数调用跟踪组件”输出的记录待测函数退出 动作的API函数,将曾保存的函数调用跟踪记录对象的持有信息传递到函数调 用跟踪组件中。
Step32.函数调用跟踪组件通过系统API获取当前运行线程的id标识符,并根 据此id标识符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出当 前线程的“线程内函数调用跟踪记录链对象”。
Step33.验证当前线程内函数调用跟踪记录链的头部所保存函数调用跟踪记录 对象,与外部传入函数调用跟踪记录对象是否匹配、相同。若不一致,则输出 错误信息,直接转向Step35,否则继续。
Step34.移除“线程内函数调用跟踪记录链”头部引用的最近一次函数调用跟 踪记录。
Step35.结束。
进一步,函数调用超时与死锁检测步骤如下:
Step41.将函数调用跟踪组件中所有的“线程内函数调用跟踪记录链对象”(可 使用多种数据结构实现集合对象)的引用信息(如对象地址)转存为一个一维 数组,以供遍历。
Step42.遍历该一维数组,设置当前数组访问下标为1,从第一个元素开始。
Step43.判断当前数组访问下标,若超出数组长度,则转向Step49,否则继 续。
Step44.根据当前数组访问下标,取得一维数组中对应的“线程内函数调用跟 踪记录链对象”。
Step45.对“线程内函数调用跟踪记录链对象”的已运行时间进行计数增加1, 表示增加一个时间单位(可自定义单位时间大小,建议值为1秒,此时间单位 对应前述独立监视线程的扫描时间周期)。
Step46.将“线程内函数调用跟踪记录链对象”的已运行时间与第一级时间计 数阈值(建议3秒以内,除非阻塞或高密度计算,否则大部分编程良好的函数 不需要运行超出1秒以上的时间)进行大小判断,也为超时判断,若超出,则 输出函数运行超时日志信息进行提示。
Step47.将“线程内函数调用跟踪记录链对象”的已运行时间与第二级时间计 数阈值(足够大值,建议30秒左右,以排除部分计算负担较重、耗时较久的函 数影响)(死锁判断)进行大小判断,若超出,则输出函数运行死锁日志信息进 行提示。
Step48.当前数组访问下标自增1,返回Step43。
Step49.结束循环。
以上发明中,涉及到同一数据结构被多个线程共享操作的,需参照公知技 术,施以加锁操作进行多线程同步。
进一步地,由于待测函数进入跟踪步骤和待测函数退出跟踪步骤中,需要 根据当前运行线程的id标识符,从“线程内函数调用跟踪记录链对象”的集合 对象中检索出对应的“线程内函数调用跟踪记录链对象”。采用本领域公知常 用的一些容器类来实现该集合对象,将会面临多线程同步、复杂或低效的查找 算法带来的性能损失,对于将会内嵌到大量待测函数中运行的代码而言,将会 显著影响整个程序的性能。
主流操作系统中线程id一般定义为4字节的整数,从检索性能和线程访问 隔离的角度考虑,定义下标从0到0xFFFFFFFF对应线程id的一维简单数组来 实现上述集合对象对于直接随机查找而言是性能最优的。但在实际中,这将会 占用至少2G以上的内存空间,并且大部分空间不会被使用到,空间利用率极 低,因此并不现实。
本发明采取组合方法解决此问题。由于线程id虽一般定义为4字节的整 数,但实际运行的进程中,线程的数量并不多,大部分线程id一般表现为4位 整数(即最高位为千位)。因此,“线程内函数调用跟踪记录链对象”的集合 对象可以使用两级数据结构进行管理。对于4位整数以内的线程id对应的线程 内函数调用跟踪记录链对象采用简单数组管理,对于4位整数以上的线程id对 应的线程内函数调用跟踪记录链对象采用本领域公知常用的一些复杂容器类 (一般为平衡二叉树、哈希表等映射类)管理。
本发明通过采用上述技术方案,与现有技术相比,具有如下优点:
(1)通过C++对象创建、销毁分别自动调用构造和析构函数的特性,简化建立 函数调用跟踪机制所需的代码,对所需跟踪的函数只需一行代码即可获得跟踪 特性的支持;
(2)采用的独立自主线程判断机制,不影响软件原有的运行逻辑,可在软件主 线程和工作线程陷入死锁时,正常执行跟踪工作;
(3)在检测到函数死锁故障前不打印不必要的日志,可避免不必要的性能损 失。
(4)采用此方法,通过增加设一个判断函数调用超时的时间阈值,还可以用于 检测函数调用是否存在设计不希望的运行性能问题。
附图说明
图1是本发明的实施例的静态结构示意图。
图2是本发明的实施例中则当某线程运行至FunctionC时,其对应线程内函数 调用跟踪记录链状态。
具体实施方式
现结合附图和具体实施方式对本发明进一步说明。
作为一个具体的实施例,如图1所示,本发明的一种基于运行期动态跟踪 的函数执行超时与死锁检测的方法,该方法主要包括:
A、在待检测函数的运行入口插入一段跟踪代码,区分待检测函数当前运 行所属线程,分别为不同的线程建立相应的数据结构,登记各个进入运行的待 检测函数的特征信息,并返回此特征信息对象的引用数据给待测函数临时保 存,对于存在嵌套调用关系的待测函数,则按进入运行的先后次序创建一个链 表数据结构对多个待检测函数特征信息进行保存;
B、在待测函数的运行出口也插入对应的跟踪代码,根据A中曾返回的特征 信息对象的访问信息,将函数特征信息对象从当前运行所属线程的数据结构中 取消登记;
C、在进程中创建一独立监视线程,以一个单位时间周期(推荐值为1秒, 避免对程序运行造成太多额外运行开销)内扫描各个线程中由于一个或多个待 测函数进入运行产生的特征信息对象,并对其进行时间计数递增,对于时间计 数超过第一级时间计数阈值(建议3秒以内,除非阻塞或高密度计算,否则大 部分编程良好的函数不需要运行超出1秒以上的时间)的待测函数,则表示其 运行时间偏长,即超时,而对于时间计数超过第二级时间计数阈值的待测函 数,则表示其运行时间过长,存在死锁可能。
为使上述技术方案的应用足够简便,本发明对其进行封装,封装为一个可 复用的函数调用跟踪组件(在Windows系统中以DLL体现)。
该函数调用跟踪组件将实现上述A、B、C三部分的主要有效实现,其中主 要包括:为多个线程各自独立维护、跟踪待测函数运行的数据结构,以及一个 独立的监视线程。
对应地,为应用此发明的待检测程序提供函数调用跟踪组件包装对象、函 数调用跟踪代理对象来运用函数调用跟踪组件。
上述函数调用跟踪组件包装对象定义为,控制函数调用跟踪组件在待测目 标程序中进行加载、启动、调用、停止、释放活动的代理类对象,为待测目标 程序使用函数调用跟踪组件提供对象级别的管理。
将上述创建函数调用跟踪组件包装对象(以下用CRTErrTrackerDllWrapper 指代,Wrapper class of dynamic link library runtime-error tracker)、 函数调用跟踪代理对象(以下用CFunctionTracker指代)、函数调用跟踪记录 (以下用CFuncInvokeRecord指代)、线程内函数调用跟踪记录链(以下 CFuncInvokeRecordChain指代)、函数调用跟踪监视器模块(以下用CMonitor 指代):
1、创建该函数调用跟踪组件包装对象(以下用CRTErrTrackerDllWrapper 指代,Wrapper class of dynamic link library runtime-error tracker)
对于将要使用本发明中这一机制的程序模块,不论是EXE可执行程序还是 DLL动态链接库,均可在程序模块中定义一个函数调用跟踪组件包装对象类型 的全局变量,以方便对函数调用跟踪组件DLL模块的进行加载、初始化、启 动、停止、释放等管理动作。
CRTErrTrackerDllWrapper的定义布局如下:

上述函数调用跟踪代理对象定义为,接收函数调用信息,通过函数调用跟 踪组件的API接口将待测目标函数信息、进入和退出动作传递进函数调用跟踪 组件中以供超时或死锁判断的代理类对象。
2、创建函数调用跟踪代理对象(以下用CFunctionTracker指代,Proxy  class of function-invoke tracker)
为了在目标程序模块中使用函数调用跟踪组件DLL来检测待测目标函数运 行中可能存在的问题,需要按一定的顺序调用函数调用跟踪组件DLL导出的两 个函数:EnterFunctionTracker、LeaveFunctionTracker。而 CFunctionTracker则是为了使调用更加方便做出的封装。
该对象使用在待测函数刚进入运行时声明局部变量的方式创建,使用对象 的构造、析构函数完成对函数调用跟踪组件DLL导出函数的调用。其创建伪代 码如下:

CFunctionTracker的定义布局如下:

函数调用跟踪组件中为多个线程独立维护、跟踪待测函数运行的数据结构 具体定义如下。
将上述A部分中提到的待检测函数特征信息对象,正式约定为“函数调用 跟踪记录”,定义为记录所跟踪目标程序模块中某个待测函数调用信息、并缓 存在函数调用跟踪组件中供监视线程检测超时或死锁的一个数据对象,其中主 要记录了待测函数的进入时间点、已进入运行后的滞留时间长度、所属的程序 模块信息(如模块名称)、特征信息(如函数名称)。
3、函数调用跟踪记录(以下用CFuncInvokeRecord指代)
CFuncInvokeRecord是函数调用跟踪组件DLL内部记录对待测函数调用动作 的数据记录对象,主要保存待测函数的信息(如名称)、运行滞留时间。当函 数调用跟踪组件DLL通过导出函数接收到待测函数进入运行的通知时创建,接 收到待测函数退出运行的通知时销毁。其中的运行滞留时间,由函数调用跟 踪监视器模块进行计数和超时判断。
CFuncInvokeRecord的定义布局如下:

其中,紧邻外层被测函数跟踪记录,指的是待测函数外部还存在其他嵌套 调用的被测函数时,外层最近的一个被测函数对应生成的函数跟踪记录。


如上述伪代码所示,如果FunctionA和FunctionB均被CFunctionTracker对象 进行跟踪时,FunctionB对应的函数跟踪记录中的“紧邻外层被测函数跟踪记 录”即是FunctionA对应的函数跟踪记录。
而函数运行滞留时间,指的是待测函数在进入运行后、退出运行前,对应 的函数跟踪记录所生存的时间。该时间变量由函数调用跟踪监视器模块 CMonitor中的独立扫描线程进行计时累加。
待测程序模块名称和待测函数名称,则是函数调用跟踪监视器模块 CMonitor在为待测函数建立对应的函数调用跟踪记录时,由待测模块通过函数 调用跟踪代理对象的构造函数逐层传入保存的两个数据。其目的在于,当函数 调用跟踪监视器模块CMonitor中的独立扫描线程检测到函数运行超时后,能具 体地输出故障模块和故障函数的信息。
待检测函数之间完全存在嵌套调用的可能性,即,一个待测函数func1进 入运行后、尚未退出前,另一个待测函数func2进入运行。对于此种情形,由 于当前线程中func1的函数调用跟踪记录尚未被删除,就会面临被func2的函 数跟踪记录覆写、从而丢失func1的函数调用跟踪记录的风险。为解决此问 题,定义线程内函数调用跟踪记录链为线程中多个嵌套进行的待测函数调用所 生成函数调用跟踪记录的一个链式数据结构,其中待测函数的函数调用跟踪记 录在链表中的先后顺序与待测函数嵌套调用的先后顺序相同。每个可能运行到 的线程均拥有一个线程内函数调用跟踪记录链。
4、线程内函数调用跟踪记录链
考虑到,多个待测函数间可能存在嵌套的调用,因此,函数调用跟踪 记录CFuncInvokeRecord需要建立对应嵌套、链式的结构进行数据保存。 又考虑到,任何一个待测函数均有可能被多个线程调用,因此,为了避免 发生跟踪混乱,需要为每一个线程都维护一个链式结构,此数据结构定义 为“线程内函数调用跟踪记录链”。
CFuncInvokeRecordChain的定义布局如下:

假设FunctionA、FunctionB、FunctionC有如下嵌套关系:


则当某线程运行至FunctionC时,其对应线程内函数调用跟踪记录链状态 如图2所示。
上述各部件,函数调用跟踪组件包装对象和函数调用跟踪代理对象位于待 测函数所属之待跟踪程序模块中。函数调用跟踪记录由线程内函数调用跟踪记 录链的链式结构所管理,而线程内函数调用跟踪记录链对象又保存在函数调用 跟踪组件为待测目标程序进程的各线程创建的一个线程内函数调用跟踪记录链 对象集合中。
函数调用跟踪组件包装对象主要管理函数调用跟踪组件的加载、启动、调 用、停止、释放,主要通过操作系统API、及函数调用跟踪组件本身输出的用 户API对函数调用跟踪组件的运行进行控制管理,同时负责将函数调用跟踪组 件输出的用户API调用信息(如函数指针方式)复制给函数调用跟踪代理对象 进行静态化保存(静态化指保存数据不受单个函数调用跟踪代理对象创建和销 毁的影响)。
函数调用跟踪代理对象则通过调用函数调用跟踪组件包装对象复制而来的 API函数指针,将待测函数进入、退出调用动作传递到函数调用跟踪组件中, 驱动函数调用跟踪组件查找当前线程对应的线程内函数调用跟踪记录链对象, 并在其中建立函数调用跟踪记录。
5、函数调用跟踪监视器模块的定义以及组成部件
函数调用跟踪监视器模块是函数调用跟踪组件DLL中的核心控制类,主要 完成对“线程内函数调用跟踪记录链”对象的创建、管理,以及一个扫描函数 调用跟踪记录中函数运行滞留时间是否超时的独立线程的创建、管理。
CMonitor的定义布局如下:

其中,扫描线程函数ScanThreadFunc,主要完成以1秒钟为间隔的定时扫 描,扫描作为参数传入的函数调用跟踪监视器模块CMonitor对象中各“线程内 函数调用跟踪记录链”对象CFuncInvokeRecordChain的当前跟踪记录 (CurRecord_Pointer所指向的函数调用跟踪记录)中的函数运行滞留时间 StayTime,对于StayTime超出预设值(如5秒以上)的,将待测程序模块名称 和待测函数名称输出为文件日志,不超出预设值的,对StayTime增加1,进行 函数运行累加计时。
启动工作函数Init_Startup主要目的是通过将扫描线程函数作为参数传递 给系统调用(此为公知技术),启动独立扫描线程。对应地,结束工作函数 Stop_Release的设计目的是停止扫描线程。
线程内函数调用跟踪记录链对象数组FuncInvokeRecordChain_Array和线 程内函数调用跟踪记录链对象映射FuncInvokeRecordChain_Map,设计用于对 “线程内函数调用跟踪记录链对象”进行分级管理。
在操作系统中,由于线程Id标识符往往设计为4个字节的整数。线程内函 数调用跟踪记录链对象数组FuncInvokeRecordChain_Array设计为用于访问进 程中实际运行的、其线程Id标识符小于某个整数值MaxThreadId的线程所对应 的线程内函数调用跟踪记录链对象的性能最优方法,线程Id标识符用作访问数 组元素的下标值。
绝大部分情况下,进程中实际运行的线程,其线程Id标识符极少超出9999 四位数字的表达范围,因此,本实施例中MaxThreadId取值20000。
对于特殊情况下,线程Id标识符超出20000的线程所对应的线程内函数调 用跟踪记录链对象则在线程内函数调用跟踪记录链对象映射 FuncInvokeRecordChain_Map中进行管理。此时,其根据线程Id标识符获取线 程内函数调用跟踪记录链对象的访问性能低于上述数组查找方式。
(1)加载初始化该函数调用跟踪组件;其中,加载初始化该函数调用跟踪组 件包括以下步骤:
Step11.待测目标程序模块在完成加载、初始化后,通过函数调用跟踪组件包装 对象加载函数调用跟踪组件,并驱动其进行初始化启动。具体过程如下。
分步骤111:调用进程创建函数调用跟踪组件包装对象,调用其组件启动 运行函数Load_Init_Startup;
分步骤112:在前述Load_Init_Startup函数中,函数调用跟踪组件包装对 象CRTErrTrackerDllWrapper负责通过Windows API函数LoadLibrary,将函数 调用跟踪组件DLL(后续可用RTErrTracker.dll指代)加载到待测目标进程中 运行,并获得LoadLibary返回的函数调用跟踪组件模块句柄保存至DLLModule 中。若同一进程中,前面已有其他程序模块通过函数调用跟踪组件包装对象执 行过函数调用跟踪组件的加载,则转分步骤四(这一点可由系统调用 LoadLibrary保证),相反,则继续分步骤113;
分步骤113:函数调用跟踪组件DLL首次加载到进程空间中后,通过声明一 个函数调用跟踪监视器类型的全局变量的方式,创建函数调用跟踪监视器模 块,其定义见前述表达,同时将函数调用跟踪监视器模块的初始化状态赋值为 假(False),代表尚未初始化;
分步骤114:函数调用跟踪组件包装对象以之前返回的函数调用跟踪组件 模块句柄DLLModule为参数,通过GetProcAddress系统调用(此处为公知技 术),取得函数调用跟踪组件DLL导出函数的函数指针进行保存,分别是以下 四个导出函数:函数调用跟踪组件DLL启动运行函数(以下用DLLInit_Startup 指代)、函数调用跟踪组件DLL结束运行函数(以下用DLLStop_Release指代)、 待测目标函数进入运行跟踪函数(以下用EnterFunctionTracker指代)、待测 目标函数退出运行跟踪函数(以下用LeaveFunctionTracker指代)。将 DLLInit_Startup、DLLStop_Release这两个导出函数的函数指针赋值保存至自 身Init_Startup_FuncPointer、Stop_Release_FuncPointer这两个静态成员 中。将EnterFunctionTracker、LeaveFunctionTracker这两个导出函数的函数 指针赋值给函数调用跟踪代理对象CFunctionTracker的 EnterFunctionTracker_FunctionPointer、 LeaveFunctionTracker_FunctionPointer这两个静态成员保存。同时,将待测 程序模块的名称字符串赋值给CFunctionTracker的静态成员ModuleName;
分步骤115:函数调用跟踪组件包装对象CRTErrTrackerDllWrapper通过前 面赋值保存的函数指针Init_Startup_FuncPointer对函数调用跟踪组件DLL导 出的DLLInit_Startup函数进行调用(通过函数指针调用函数是一项公知技 术);
分步骤116:在函数调用跟踪组件DLL的启动运行函数DLLInit_Startup 中,对函数调用跟踪监视器模块进行初始化,若其初始化状态为真(True), 则结束,否则,继续下一步骤;
分步骤117:将函数调用跟踪组件DLL中函数调用跟踪监视器模块的初始化 状态设置为真(True)。
Step12.函数跟踪组件在初始化过程中首先创建一个“线程内函数调用跟踪记 录链对象的集合”数据结构。
进一步具体地,由函数调用跟踪监视器模块CMonitor负责创建线程内函数 调用跟踪记录链对象数组FuncInvokeRecordChain_Array和线程内函数调用跟 踪记录链对象映射FuncInvokeRecordChain_Map对线程内函数调用跟踪记录链 对象按线程Id进行分级管理,以实现“线程内函数调用跟踪记录链对象的集 合”这一数据结构。
进一步地,线程内函数调用跟踪记录链对象的分级管理规则为:线程内函 数调用跟踪记录链对象数组FuncInvokeRecordChain_Array用于存储线程Id小 于20000的线程所对应的线程内函数调用跟踪记录链对象,线程内函数调用跟 踪记录链对象映射FuncInvokeRecordChain_Map用于存储线程Id大于20000的 线程所对应的线程内函数调用跟踪记录链对象。
Step13.函数调用跟踪组件在初始化过程的最后,创建一独立工作线程,用于 对运行了待测函数的各个线程所对应的线程内函数调用跟踪记录链对象进行扫 描检测。
具体地,由函数调用跟踪监视器模块CMonitor负责启动其内部的主动扫描 线程ScanThreadFunc(通过向系统调用_beginthreadex传入线程函数启动线程 是一项公知技术);
(2)待测函数进入跟踪步骤
Step21.待测函数进入运行后,创建“函数调用跟踪代理对象”。
具体为,待测函数进入运行后,立即创建一个函数调用跟踪代理对象,并 向其传递待测函数的基本信息,本实施例中仅传入待测函数的名称字符串,作 为函数调用跟踪代理对象的构造函数的参数。此处的特殊作法是,用作参数的 待测函数的函数名字符串是使用常量字符串的方式编译进待测程序模块(指操 作系统中编译为可执行代码的程序模块,例如windows操作系统下的exe、dll 文件)的静态存储区中。例如,形如CFunctionTracker  tracker(“FunctionA”)的代码中,字符串“FunctionA”将被编译进静态存 储区,当待测程序模块被加载后,该字符串常量将始终存在,有着固定的访问 地址,可以直接复制字符串常量的首地址进行保存使用,如此可以避免在函数 调用跟踪组件DLL内部的函数调用跟踪记录对象中重新分配内存进行字符串内 容的拷贝复制,可以显著地提升性能;
Step22.“函数调用跟踪代理对象”创建时自动调用构造函数,并在其中调用 “函数调用跟踪组件”输出的记录待测函数进入动作的API函数,将待测函数 进入动作和待测函数信息一并传递到函数调用跟踪组件中。
具体为,函数调用跟踪代理对象在构造时(指编译器自动生成的代码调用 对象的构造函数这一过程,为公知技术),通过函数调用跟踪代理对象的待测 目标函数进入运行跟踪函数指针EnterFunctionTracker_FuncPointer,调用函 数调用跟踪组件DLL的导出函数EnterFunctionTracker,调用时将函数调用跟 踪代理对象在前面步骤中复制保存的待测程序模块名称ModuleName和构造函数 传入的待测函数名称字符串FuncName作为参数传入;
Step23.函数调用跟踪组件通过系统API获取当前运行线程的id标识符,并根 据此id标示符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出对 应的“线程内函数调用跟踪记录链对象”。具体过程如下。
分步骤231,函数调用跟踪组件DLL运行待测目标函数进入运行跟踪函数 EnterFunctionTracker,获取当前执行线程的线程Id标识符。若线程Id标识 符小于等于20000,则以线程Id标识符为下标,从函数调用跟踪监视器模块的 线程内函数调用跟踪记录链对象数组中取出对应的线程内函数调用跟踪记录链 对象,结束,否则,继续进入分步骤232;
分步骤232:对于线程Id标识符大于20000,从函数调用跟踪监视器模块 的线程内函数调用跟踪记录链对象映射Map中查找取出对应的线程内函数调用 跟踪记录链对象(基于Map的Key-value查找属公知技术,一般基于平衡二叉 树或哈希表技术),若查找失败,则表示所需对象尚未创建,可新建一个线程 内函数调用跟踪记录链对象加入函数调用跟踪监视器模块的线程内函数调用跟 踪记录链对象映射Map对象中。
Step24.为当前待测函数生成新的函数调用跟踪记录对象,同时在其中保存外 部通过函数调用参数逐层传入的待测函数信息。具体过程如下。
分步骤241:创建一个新的函数调用跟踪记录,其定义如前所述,将步骤 二中传入的待测程序模块名称ModuleName和构造函数传入的待测函数名称字符 串FuncName对应的字符串首指针分别分别复制到函数调用跟踪记录的待测程序 模块名称ModuleName和待测函数名称FuncName这两个成员变量上进行保存。
分步骤242:将新创建的函数调用跟踪记录的函数运行滞留时间StayTime 初始化赋值为0;
Step25.将新创建的函数调用跟踪记录对象,插入到对应的线程内函数调用跟 踪记录链的头部,作为当前线程的最近一次函数调用跟踪记录。具体过程如 下。
分步骤251:检查当前线程内函数调用跟踪记录链对象的当前跟踪记录指 针引用CurRecord_Poniter,如为空(NULL),则直接转分步骤253,否则,继 续下一步骤;
分步骤252:将当前线程内函数调用跟踪记录链对象的当前跟踪记录指针 引用CurRecord_Poniter赋值复制给Step24中新创建的函数调用跟踪记录的紧 邻外层被测函数跟踪记录PrevTracker_Pointer;
分步骤253:将步骤五中新创建的函数调用跟踪记录的指针引用赋值复制 给当前线程内函数调用跟踪记录链对象的当前跟踪记录指针引用 CurRecord_Poniter;
Step26.最终,将新创建的函数调用跟踪记录对象的持有信息(如对象地址)逐 层返回给“函数调用跟踪代理对象”保存,留待待测函数退出时使用。
具体指,将新创建函数调用跟踪记录的指针引用,返回给Step21中的函数 调用跟踪代理对象保存,具体保存在其内部跟踪记录对象指针 InternalTracker_Pointer中。
(3)待测函数退出跟踪步骤:
Step31.待测函数退出运行前,并无论在函数内部何处返回,受益于编程语言 提供的特性,“函数调用跟踪代理对象”将被自动销毁,其析构函数自动发生 调用,通过在其析构函数内执行“函数调用跟踪组件”输出的记录待测函数退 出动作的API函数,将曾保存的函数调用跟踪记录对象的持有信息传递到函数 调用跟踪组件中。具体过程如下:
分步骤311:待测函数正常或异常退出后,函数调用跟踪代理对象将析构 (指编译器自动生成的代码调用对象的析构函数这一过程,为公知技术)销 毁;
分步骤312:函数调用跟踪代理对象在析构时,通过函数调用跟踪代理对 象的待测目标函数退出运行跟踪函数指针 LeaveFunctionTracker_FuncPointer,调用函数调用跟踪组件DLL的导出函数 LeaveFunctionTracker,同时传递待测函数进入跟踪步骤十返回给函数调用跟 踪代理对象的内部跟踪记录对象指针InternalTracker_Pointer保存的函数调 用跟踪记录指针引用作为参数,调入函数调用跟踪组件中运行;
Step32.函数调用跟踪组件通过系统API获取当前运行线程的id标识符,并根 据此id标识符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出当 前线程的“线程内函数调用跟踪记录链对象”。
进一步更佳的实现是,根据传入的函数调用跟踪记录的所属的线程内函数 调用跟踪记录链对象指针引用Chain_Pointer,直接获取当前线程内函数调用 跟踪记录链对象;
Step33.验证当前线程内函数调用跟踪记录链的头部所保存函数调用跟踪记录 对象,与外部传入函数调用跟踪记录对象是否匹配、相同。若不一致,则输出 错误信息,直接转向Step35,否则继续。
Step34.移除“线程内函数调用跟踪记录链”头部引用的最近一次函数调用跟 踪记录。具体过程如下。
分步骤341:将当前线程内函数调用跟踪记录的紧邻外层被测函数跟踪记 录PrevTracker_Pointer赋值复制给当前线程内函数调用跟踪记录链对象的当 前跟踪记录指针引用CurRecord_Poniter,将传入的函数调用跟踪记录从当前 线程内函数调用跟踪记录链上移除;
分步骤342:检查当前线程内函数调用跟踪记录链对象的当前跟踪记录指 针引用CurRecord_Poniter目前是否为空(NULL),如为空,转分步骤344,否 则继续下一步骤;
分步骤343:将传入移除的函数调用跟踪记录的函数运行滞留时间 StayTime,累加到当前线程内函数调用跟踪记录链对象的当前跟踪记录指针引 用CurRecord_Poniter所指向的函数调用跟踪记录的函数运行滞留时间 StayTime上;
分步骤344:检查传入移除的函数调用跟踪记录的函数运行滞留时间 StayTime,如超出预设值,则可输出运行超时日志用于分析;
分步骤345:从内存中销毁、删除传入移除的函数调用跟踪记录后,结 束;
Step35.结束。
(4)函数调用超时与死锁检测步骤:
Step41.将函数调用跟踪组件中所有的“线程内函数调用跟踪记录链对象”(可 使用多种数据结构实现集合对象)的引用信息(如对象地址)转存为一个一维 数组,以供遍历。具体过程如下。
分步骤411:函数调用跟踪监视器模块的主动监视线程创建后进入运行, 判断调用进程是否要求退出,如果要求退出,则转分步骤412,否则转分步骤 413;
分步骤412:对所有的线程内函数调用跟踪记录链执行清理动作,释放资 源后,退出主动监视线程,结束;
分步骤413:主动监视线程执行系统调用Sleep(1000),主动睡眠1秒钟, 防止函数过度占用CPU资源;
分步骤414:主动监视线程睡眠时间到,由操作系统主动唤醒后,重新从 ini配置文件中,读取函数运行超时、运行死锁判断的时间阈值,赋值给函数 调用跟踪组件DLL模块中的全局整型变量timeout_max_value、 deadlock_max_value,可起到配置刷新的效果,可支持运行时实时修改设置;
分步骤415:主动监视线程扫描所有函数调用跟踪监视器模块中通过数组 和映射管理的所有线程内函数调用跟踪记录链对象,检查其中存储的当前跟踪 记录指针引用CurRecord_Poniter是否为空(NULL),若非空,则将其输出到 一个临时数组temp_chain_array中;
Step42.遍历该一维数组,设置当前数组访问下标为1,从第一个元素开始。
具体指,设置循环整型变量index为0,从一维数组temp_chain_array的 第一个元素开始循环访问。
Step43.判断当前数组访问下标,若超出数组长度,则转向Step49,否则继 续。
具体指,判断整型变量index小于临时数组temp_chain_array的元素个数 count的表达式是否为真,若非真,则结束循环,直接结束,若为真,继续下 一步骤;
Step44.根据当前数组访问下标,取得一维数组中对应的“线程内函数调用跟 踪记录链对象”。
具体指,从临时数组temp_chain_array中获取下表为index的线程内函数 调用跟踪记录链对象,通过CurRecord_Poniter字段取得当前跟踪记录。
Step45.对“线程内函数调用跟踪记录链对象”的已运行时间进行计数增加1, 表示增加一个时间单位(可自定义单位时间大小,建议值为1秒,此时间单位 对应前述独立监视线程的扫描时间周期)。
具体指,对当前跟踪记录的函数运行滞留时间StayTime递增1。
Step46.将“线程内函数调用跟踪记录链对象”的已运行时间与第一级时间计 数阈值(建议3秒以内,除非阻塞或高密度计算,否则大部分编程良好的函数 不需要运行超出1秒以上的时间)进行大小判断,也为超时判断,若超出,则 输出函数运行超时日志信息进行提示。
具体指,判断StayTime小于函数调用跟踪组件DLL模块中的全局整型变量 timeout_max_value的表达式是否为真,若非真,则输出当前跟踪记录的待测 程序模块名称ModuleName和待测函数名称FuncName(同时附加“运行超时”字 符串信息)到文件日志中。
Step47.将“线程内函数调用跟踪记录链对象”的已运行时间与第二级时间计 数阈值(足够大值,建议30秒左右,以排除部分计算负担较重、耗时较久的函 数影响)(死锁判断)进行大小判断,若超出,则输出函数运行死锁日志信息进 行提示。
具体指,判断StayTime小于函数调用跟踪组件DLL模块中的全局整型变量 deadlock_max_value的表达式是否为真,若非真,则输出当前跟踪记录的待测 程序模块名称ModuleName和待测函数名称FuncName(同时附加“运行可能死 锁”字符串信息)到文件日志中。
Step48.当前数组访问下标自增1,返回Step43。
具体指,整型变量index递增1,转向step43。
Step49.结束循环。
实施例中,主要给出了判断函数运行超时的方法,本发明又认为函数的足 够长时间运行超时可视作存在死锁的可能。因此,本发明通过设定一个足够大 的函数运行超时判断时间阈值(可定义为函数运行死锁判断时间阈值),结合 超时判断方法来检测可能的死锁,而非通过严格的死锁逻辑条件来判断。
以上发明中,涉及到同一数据结构被多个线程共享操作的,需参照公知技 术,施以加锁操作进行多线程同步。
但进一步地,由于步骤(2)和步骤(3)中,需要根据当前运行线程的id 标识符,从“线程内函数调用跟踪记录链对象”的集合对象中检索出对应的 “线程内函数调用跟踪记录链对象”。采用本领域公知常用的一些容器类来实 现该集合对象,将会面临多线程同步、复杂或低效的查找算法带来的性能损 失,对于将会内嵌到大量待测函数中运行的代码而言,将会显著影响整个程序 的性能。
主流操作系统中线程id一般定义为4字节的整数,从检索性能和线程访问 隔离的角度考虑,定义下标从0到0xFFFFFFFF对应线程id的一维简单数组来 实现上述集合对象对于直接随机查找而言是性能最优的。但在实际中,这将会 占用至少2G以上的内存空间,并且大部分空间不会被使用到,空间利用率极 低,因此并不现实。
本发明采取组合方法解决此问题。由于线程id虽一般定义为4字节的整 数,但实际运行的进程中,线程的数量并不多,大部分线程id一般表现为4位 整数(即最高位为千位)。因此,“线程内函数调用跟踪记录链对象”的集合 对象可以使用两级数据结构进行管理。对于4位整数以内的线程id对应的线程 内函数调用跟踪记录链对象采用简单数组管理,对于4位整数以上的线程id对 应的线程内函数调用跟踪记录链对象采用本领域公知常用的一些复杂容器类 (一般为平衡二叉树、哈希表等映射类)管理。
尽管结合优选实施方案具体展示和介绍了本发明,但所属领域的技术人员 应该明白,在不脱离所附权利要求书所限定的本发明的精神和范围内,在形式 上和细节上可以对本发明做出各种变化,均为本发明的保护范围。

一种基于运行期动态跟踪的函数执行超时与死锁检测方法.pdf_第1页
第1页 / 共22页
一种基于运行期动态跟踪的函数执行超时与死锁检测方法.pdf_第2页
第2页 / 共22页
一种基于运行期动态跟踪的函数执行超时与死锁检测方法.pdf_第3页
第3页 / 共22页
点击查看更多>>
资源描述

《一种基于运行期动态跟踪的函数执行超时与死锁检测方法.pdf》由会员分享,可在线阅读,更多相关《一种基于运行期动态跟踪的函数执行超时与死锁检测方法.pdf(22页珍藏版)》请在专利查询网上搜索。

本发明涉及计算机技术领域,一种基于运行期动态跟踪的函数执行超时与死锁检测的方法包括A、在待检测函数的运行入口插入一段跟踪代码,区分待检测函数当前运行所属线程,登记各个进入运行的待检测函数的特征信息,并返回此特征信息对象的引用数据给待测函数临时保存。B、在待测函数的运行出口也插入对应的跟踪代码,根据A中曾返回的特征信息对象的访问信息,将函数特征信息对象从当前运行所属线程的数据结构中取消登记。C、在进。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 物理 > 计算;推算;计数


copyright@ 2017-2020 zhuanlichaxun.net网站版权所有
经营许可证编号:粤ICP备2021068784号-1