如何使旧的C代码库具有许多全局变量可重入

时间:2013-12-04 07:47:30

标签: c++ c refactoring automated-refactoring reentrancy

我正在使用一个大型的旧C代码库(一个解释器),它使用全局变量很多,结果是我不能同时拥有它的两个实例。是否有一种简单(理想的自动化)方法将此代码转换为可重入的内容?即一些重构工具,它会使所有全局变量成为结构的一部分,并将指针添加到所有变量之前?

我可以转换为C ++并将整个事物包装在类定义中吗?

6 个答案:

答案 0 :(得分:1)

我不知道任何针对此类问题的“现成”解决方案。

作为一般规则,全局变量将使代码难以重入。

如果你可以删除所有全局变量[只需删除全局变量并查看编译器错误的位置]。用结构替换全局变量,然后使用传递的每个实例的结构,你就可以完成了(只要解释器​​实例的状态是独立的,并且实例不需要知道每个其他)。 [当然,您可能需要使用多个结构来解决问题,但您的全局变量应该可以“坚持结构”]。

当然,将结构和代码放在一起作为C ++类(可能有较小的类作为解决方案的一部分)将是“下一步”,但如果你这样做并不完全是直截了当的不熟悉C ++和类设计。

答案 1 :(得分:1)

你是否试图让它重新进入以便能够使它成为多线程,并在线程之间划分工作? 如果是这样,我会考虑将其作为多进程,而不是多线程,

答案 2 :(得分:1)

我建议您将项目转换为C ++ 11项目,并将所有静态变量更改为threadlocal

根据项目的大小,这可能长达数天。在某些情况下,这将有效。

答案 3 :(得分:0)

我通常使用解释器直接使用实例变量而不是全局变量。不确定你在解释什么,但是可以传入一个文件路径或字符串容器,该类用内部线程解释,因此封装整个解释运行。

答案 4 :(得分:0)

可以将整个事物包装在类定义中,但它不适用于获取函数地址并将它们传递给C代码的代码。此外,将大型遗留代码库转换为可由C ++编译器编译是非常繁琐的,它可能超过了手动删除全局变量的努力。

除此之外,您有两种选择:

  1. 由于您需要重入实现线程,因此最简单的方法是声明所有全局变量 thread-local 。如果你有一个supports thread-locals的C编译器,这通常就像在每次声明之前打一个__thread(或其他编译器特定的关键字)一样简单。然后,只需创建一个新线程并以正常方式初始化解释器,即可创建一个新的解释器。

  2. 如果你不能使用__thread或同等的,那么你必须做更多的步法。您需要将所有全局变量放在结构中,并用foo替换对全局变量get_ctx()->foo的每次访问。这很乏味,但很简单。完成后,get_ctx()可以使用API of your choosing分配并返回线程局部解释器状态。

答案 5 :(得分:0)

可以处理C语言的程序转换工具可以自动执行此类更改。 它需要能够将每个符号解析为其声明,并且预处理器条件可能很麻烦。我会说出一个,但是当我那样做时,狂热者会反对。

你的包含全局变量的结构的解决方案是正确的想法;您需要重写,用槽成员替换每个全局声明,并且每次访问全局都可以访问相应的struct成员。

剩下的问题是,struct指针来自哪里?一个答案是在切换线程时多路复用的全局变量;如果在您的操作系统下可用,则更好的答案是从线程局部变量获取结构指针。