Perhaps there is something that eluded me, but ...
... Global variables are shared between threads, not processes ...
This means that in your case you can have two processes of the same C program, and they will not interfere with one another if they do not work with shared technology memory.
... if you need two instances of C code running in the same process ...
Then you are screwed.
TLS, maybe?
Either you can run them in separate threads, or declare global variables as Thread-Local-Storage variables. For example, in Visual C ++, the following code:
int myGlobalVariable = 42 ; // Global variable __declspec(thread) int myTLSVariable = 42 ; // Thread local variable
Each thread will have its own version of the variable. Thus, at the end of the stream, you can copy the contents to another location.
Code rewriting ...
You do not need to add a C ++ layer to it. You can save your C code and declare all your global variables in the structure:
int iMyGlobalVariable = 42 ; const char * strMyGlobalString = NULL ; short iMyShortData = 7 ; typedef struct MyStruct { int iMyGlobalVariable ; const char * strMyGlobalString ; short iMyShortData ; } MyStruct ;
And then you modify the function prototypes to take a pointer to this structure as the first parameter, and then instead of changing the global variable, you change the struct element:
int foo(char *p) { iMyShortData = 55 ; fooAgain("Hello World", 42) ; }
which become:
int foo(MyStruct * s, char *p) { s->iMyShortData = 55 ; fooAgain(s, "Hello World", 42) ; }
Then, basically, instead of calling the first function, you call it by pointing it to a pointer to the correct structure. Instead:
int main(int argc, char * argv[]) { bar(42, 55) ; }
You write:
int main(int argc, char * argv[]) { MyStruct A = { } ; MyStruct B = { } ; bar(&A, 42, 55) ; bar(&B, 42, 55) ; return 0 ; }
In the above example, two are called one after the other, but you can start threads instead.
Saving global status?
If your code is single-threaded, you can alternate calls for the first instance and call the second, saving / reloading the global state. Let the same structure be used:
int iMyGlobalVariable = 42 ; short iMyShortData = 7 ; void saveState(MyStruct * s) { s->iMyGlobalVariable = iMyGlobalVariable ; s->iMyShortData = iMyShortData ; } void resetState(const MyStruct * s) { iMyGlobalVariable = s->iMyGlobalVariable ; iMyShortData = s->iMyShortData ; }
Then you call the save and reset functions if necessary:
int main(int argc, char * argv[]) { MyStruct A = { } ; MyStruct B = { } ; resetState(&A) ; bar(42, 55) ; saveState(&A) ; resetState(&B) ; bar(42, 55) ; saveState(&B) ; resetState(&A) ; foo("Hello World", 3.14159) ; saveState(&A) ; resetState(&B) ; foo("Hello World", 3.14159) ; saveState(&B) ; return 0 ; }
This can be wrapped with C ++ code to automatically wrap the resetState / saveState functions. For instance:
struct MyWrapper { void foo(const char * p, double d) { resetState(&m_s) ; foo(p, d) ; saveState(&m_s) ; } void bar(int i, short i2) { resetState(&m_s) ; bar(i, i2) ; saveState(&m_s) ; } MyStruct m_s ; } ;
What do you allow to overwrite main as:
int main(int argc, char * argv[]) { MyWrapper A ; MyWrapper B ; A.bar(42, 55) ; B.bar(42, 55) ; A.foo("Hello World", 3.14159) ; B.foo("Hello World", 3.14159) ;
It looks much better than version C. However, MyWrapper is not thread safe ...
Conclusion
The first solution (TLS) is a quick solution, while the second is a refactoring of the code to write it correctly (there are very good reasons that the global variables frowned on, and apparently you came across one of them), and the third is a “hack,” which allows you to alternate between two calls.
Of all three solutions, only the second will allow you to easily wrap this code inside reliable, thread-safe C ++ classes, if necessary.