C++ 如何使一个有许多全局可重入的旧C代码库

C++ 如何使一个有许多全局可重入的旧C代码库,c++,c,refactoring,automated-refactoring,reentrancy,C++,C,Refactoring,Automated Refactoring,Reentrancy,我正在使用一个大型的、旧的C代码库(一个解释器),它大量使用全局变量,结果是我不能同时拥有它的两个实例。有没有一种直接的(理想情况下是自动的)方法将此代码转换为可重入的代码?i、 一些重构工具,可以使所有全局变量成为结构的一部分,并在指向所有变量的指针前面加上前缀 我可以转换为C++,并用一个类定义包装整个东西吗?< /p> 我不知道有任何“准备好”的解决方案来解决这类问题。 一般来说,全局变量会使代码难以重入 如果您可以删除所有全局变量[只需删除全局变量并查看哪里会出现编译器错误]。用一个结构

我正在使用一个大型的、旧的C代码库(一个解释器),它大量使用全局变量,结果是我不能同时拥有它的两个实例。有没有一种直接的(理想情况下是自动的)方法将此代码转换为可重入的代码?i、 一些重构工具,可以使所有全局变量成为结构的一部分,并在指向所有变量的指针前面加上前缀

我可以转换为C++,并用一个类定义包装整个东西吗?< /p> 我不知道有任何“准备好”的解决方案来解决这类问题。 一般来说,全局变量会使代码难以重入

如果您可以删除所有全局变量[只需删除全局变量并查看哪里会出现编译器错误]。用一个结构替换globals,然后对每个传递的实例使用一个结构,这样就基本完成了(只要解释器实例的状态是独立的,并且实例之间不需要相互了解)。[当然,您可能需要不止一个结构来解决问题,但您的全局变量应该可以“粘在一个结构中”]


当然,将结构和代码作为一个C++类(可以作为解决方案的一部分而具有较小的类)一起是下一步,但是如果你不熟悉C++和类设计,那么它不是完全直接的。p> 您是否试图使其可重入,以便能够使其成为多线程,并在线程之间分配工作?
如果是这样,我会考虑多进程,而不是Muly线程,

我通常用解释器做的是直接使用一个实例VAR而不是全局的类。不确定要解释什么,但可以通过内部线程传入类解释的文件路径或字符串容器,从而封装整个解释运行。

可以将整个内容封装在类定义中,但它不适用于获取函数地址并将其传递给C代码的代码。此外,将大型遗留代码库转换为C++编译器可编译的程序是冗长的,这可能超过手工删除全局变量的努力。 除此之外,您有两种选择:

  • 因为您需要可重入性来实现线程,所以可能最容易将所有全局变量声明为线程局部变量。如果您有一个这样的C编译器,这通常就像在每次声明之前打一个
    \u线程
    (或其他编译器特定的关键字)一样简单。然后,只需创建一个新线程并以正常方式初始化解释器,即可创建一个新的解释器

  • 如果你不能使用
    \u螺纹
    或等效工具,那么你必须多做一些步法。您需要将所有全局变量放置在一个结构中,并将对全局变量
    foo
    的每次访问替换为
    get\u ctx()->foo
    。这很乏味,但很简单。完成后,
    get_ctx()
    可以使用一个函数分配并返回线程本地解释器状态


  • 一个能够处理C语言的程序转换工具将能够自动化这些更改。 它需要能够将每个符号解析为它的声明,而预处理器条件可能会带来麻烦。我想列举一个,但当我这么做的时候,狂热者会反对

    您对包含全局变量的结构的解决方案是正确的想法;您需要重写,用插槽成员替换每个全局声明,用对相应结构成员的访问替换对全局的访问


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

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


    根据项目的大小,这可能需要几天的工作。在某些情况下,这会起作用。

    您所说的“实例”到底是什么意思?您应该能够毫无问题地运行该程序两次。如果你指的是代表解释器的某个结构的实例,那就不同了。第二,“大”有多大?你有多少时间来做这件事?@arne“large”=50k sloc,当然不是我手头有事情要做的时候了。我所说的“实例”是指两个运行不同代码的独立解释器。我希望能够在单独的线程中完成这一操作,因此需要真正重新启动的东西——将所有的全局对象推到C++类中作为实例VARS。为什么它不是straghtforward?应该可以工作,不是吗?@MartinJames获取函数地址并将其传递给C代码的代码肯定会中断。@user4815162342-对于成员函数,肯定会中断。我有点假设OP不会这样做:)@MartinJames我理解OP的想法是将几乎整个代码库包装到
    类foo{…}
    ,以便全局变量成为类成员,C函数成为类成员函数。这将神奇地将所有global转换为成员,只需对遗留代码库进行最小的更改。虽然是一个好主意,但我认为它会打破,首先是因为用C++编译一个巨大的C代码库比看起来困难,第二个原因是指针指向函数,可能还有其他高级C特征。@ USER415162442-OK,公平点。我还进行C/C++互操作,因此我理解可能存在“问题”,例如,设置回调但没有辅助“void*”参数的C调用:((这使得解释器实例之间的通信变得困难。@yosim还有,这可能有一天会出现在iOS或Android上,因此多进程不是一个选项。@Martin,关于解释器进程之间的通信,您可以查看