user1494080
user1494080

Reputation: 2124

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.

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. 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.

However, it should be possible that there are multiple instances of LinEqSolver used by different threads. This requires that each instance/each thread has its own copies of the global variables in lineq.c. How can this be achieved, if we don't want to modify the 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. Then, each instance of LinEqSolver would operate on its private copy of the former globale variables. 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.

What other possibilities do I have where the actual code to solve linear equations stays in lineq.c and is just called from LinEqSolver?

Upvotes: 1

Views: 524

Answers (3)

Kirill Kobelev
Kirill Kobelev

Reputation: 10557

You can use thread_local keyword from C++11. 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. On all other threads their initial values will be zeroes.

Upvotes: 1

Pete
Pete

Reputation: 4812

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.

It is then easy to wrap this with a c++ class and have an instance per thread etc.

Another alternative would be to modify the c file to use __declspec(thread) or similar. However if you plan to put this code in a dll then you can expect insurmountable problems with that (on Windows, at least).

Upvotes: 0

4566976
4566976

Reputation: 2499

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. Unfortunately RTLD_PRIVATE isn't supported by glibc. 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. lineq.c remains untouched.

Upvotes: 1

Related Questions