[英]Integrating legacy C code in multi-threaded C++ code
Assume we have a legacy C file with some functions to solve linear equations and several corresponding global variables. 假设我们有一个旧的C文件,其中包含一些函数来求解线性方程式和几个相应的全局变量。
lineq.c: lineq.c:
/* macro definitions */
...
/* global vars */
...
/* some functions that make use of above variables */
void solveLinEq(...);
Now we want to use this legacy library in a modern multi-threaded C++ application. 现在,我们想在现代多线程C ++应用程序中使用此旧版库。 Therefore, we want to write a kind of wrapper class
LinEqSolver
that provides an OO interface for solving linear equations and internally calls the functions of our legacy C library. 因此,我们要编写一种包装类
LinEqSolver
,它提供用于求解线性方程式的OO接口,并在内部调用旧版C库的函数。
However, it should be possible that there are multiple instances of LinEqSolver
used by different threads. 但是,应该有可能不同线程使用了多个
LinEqSolver
实例。 This requires that each instance/each thread has its own copies of the global variables in lineq.c
. 这就要求每个实例/每个线程在
lineq.c
都有自己的全局变量lineq.c
。 How can this be achieved, if we don't want to modify the lineq.c
? 如果我们不想修改
lineq.c
,如何实现?
A possible solution I can imagine is to copy the global variables and the functions from the C file into the class LinEqSolver
, making them data and function members. 我可以想像的一种可能的解决方案是将全局变量和函数从C文件复制到
LinEqSolver
类中,使它们成为数据和函数成员。 Then, each instance of LinEqSolver
would operate on its private copy of the former globale variables. 然后,
LinEqSolver
每个实例LinEqSolver
将在其以前的globale变量的私有副本上进行操作。 However, this copy-paste programming style is rather bad, especially when there is an update to lineq.c
and we need to copy-paste the changes into our code again. 但是,这种复制粘贴编程风格非常糟糕,尤其是在更新
lineq.c
,我们需要再次将更改复制粘贴到我们的代码中。
What other possibilities do I have where the actual code to solve linear equations stays in lineq.c
and is just called from LinEqSolver
? 我还有什么其他可能性可以将用于求解线性方程式的实际代码保留在
lineq.c
,而只是从LinEqSolver
?
You could put lineq.c
in a shared object and load it multiple times with dlopen
and RTLD_PRIVATE
and use dlsym
for each thread, so the global variables are separate for every thread. 您可以将
lineq.c
放在共享对象中,并使用dlopen
和RTLD_PRIVATE
多次加载它, RTLD_PRIVATE
每个线程使用dlsym
,因此对于每个线程,全局变量都是独立的。 Unfortunately RTLD_PRIVATE
isn't supported by glibc. 不幸的是,glibc不支持
RTLD_PRIVATE
。 Workaround for this would be to copy the shared object for every thread with a distinct name and use dlopen
to the copy of the shared object with RTLD_LOCAL
. 解决方法是将每个线程的共享对象复制为不同的名称,并使用
dlopen
到RTLD_LOCAL
共享对象的副本中。 lineq.c
remains untouched. lineq.c
保持不变。
You can use thread_local
keyword from C++11. 您可以使用C ++ 11中的
thread_local
关键字。 This will work well if your function always initializes all needed static variables in the beginning. 如果您的函数始终在开始时初始化所有需要的静态变量,则此方法将很好地工作。
If you have more complex picture - more work will be needed. 如果您的图片更复杂-将需要做更多的工作。 For example:
例如:
int myVar1, myVar2;
void InitStaticVars()
{
....
}
void solveLinEq(...);
If you will simply add thread_local
specifier to the variables above and call initialization function at the beginning of your program, it will initialize these variables only for the calling thread. 如果仅在上述变量中添加
thread_local
说明符并在程序的开头调用初始化函数,则它将仅为调用线程初始化这些变量。 On all other threads their initial values will be zeroes. 在所有其他线程上,它们的初始值为零。
I would just bite the bullet and modify it to add the globals into a struct that should be passed as a pointer to all calls in lineq.c. 我只是硬着头皮修改它,将全局变量添加到结构中,该结构应作为指向lineq.c中所有调用的指针传递。
It is then easy to wrap this with a c++ class and have an instance per thread etc. 然后可以很容易地用c ++类包装它,并且每个线程都有一个实例等。
Another alternative would be to modify the c file to use __declspec(thread) or similar. 另一种选择是将c文件修改为使用__declspec(thread)或类似文件。 However if you plan to put this code in a dll then you can expect insurmountable problems with that (on Windows, at least).
但是,如果您打算将此代码放在dll中,则可能会遇到无法克服的问题(至少在Windows上)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.