Возможно, что-то ускользнуло от меня, но ...
... Глобальные переменные распределяются между потоками, а не процессами ...
Это означает, что в вашем случае вы можетеу меня работают два процесса одной и той же программы на C, и они не будут мешать одному другому, если они не работают с общей памятью процесса.
... Если вам нужны два экземпляра кода C, работающего втот же процесс ...
Тогда вы облажались.
TLS, возможно?
Либо вы можете запустить их в отдельных потоках и объявить глобальные переменные как Thread-Переменные локального хранилища.Например, в Visual C ++ следующий код:
int myGlobalVariable = 42 ; // Global variable
__declspec(thread) int myTLSVariable = 42 ; // Thread local variable
Каждый поток будет иметь свою собственную версию переменной.Таким образом, в конце потока вы можете скопировать содержимое в другое место.
Переписать код ...
Вам не нужно добавлять слой C ++ к этому.Вы можете сохранить свой код C и объявить все свои глобальные переменные в структуре:
/* C global variable */
int iMyGlobalVariable = 42 ;
const char * strMyGlobalString = NULL ;
short iMyShortData = 7 ;
/* C struct */
typedef struct MyStruct
{
int iMyGlobalVariable ;
const char * strMyGlobalString ;
short iMyShortData ;
}
MyStruct ;
И затем вы модифицируете прототипы функций, чтобы принимать указатель на эту структуру в качестве первого параметра, а затем вместоизменяя глобальную переменную, вы изменяете член структуры:
/* old function */
int foo(char *p)
{
/* fudge with the global variables */
iMyShortData = 55 ;
/* etc. */
fooAgain("Hello World", 42) ;
}
, который становится:
/* new function */
int foo(MyStruct * s, char *p)
{
/* fudge with the struct variables */
s->iMyShortData = 55 ;
/* etc. */
fooAgain(s, "Hello World", 42) ;
}
Затем в основной вместо вызова первой функции вы вызываете ее, даваяэто указатель на правильную структуру.Вместо:
int main(int argc, char * argv[])
{
bar(42, 55) ;
}
Вы пишете:
int main(int argc, char * argv[])
{
MyStruct A = { /* initialize A's members if needed */ } ;
MyStruct B = { /* initialize B's members if needed */ } ;
bar(&A, 42, 55) ;
bar(&B, 42, 55) ;
return 0 ;
}
В приведенном выше примере они вызываются один за другим, но вместо этого вы можете запускать потоки.
Сохранение глобального состояния?
Если ваш код однопоточный, вы можете чередовать вызовы для первого экземпляра и вызовы для второго, сохраняя / сбрасывая глобальное состояние.Давайте используем ту же структуру, что и выше:
/* C global variable */
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 ;
}
И затем, при необходимости, вы вызываете функции сохранения и сброса:
int main(int argc, char * argv[])
{
MyStruct A = { /* initialize A's members if needed */ } ;
MyStruct B = { /* initialize B's members if needed */ } ;
resetState(&A) ; /* now, we work on A */
bar(42, 55) ;
saveState(&A) ; /* we save the progress on A */
resetState(&B) ; /* now, we work on B */
bar(42, 55) ;
saveState(&B) ; /* we save the progress on B */
resetState(&A) ; /* now, we work on A */
foo("Hello World", 3.14159) ;
saveState(&A) ; /* we save the progress on A */
resetState(&B) ; /* now, we work on B */
foo("Hello World", 3.14159) ;
saveState(&B) ; /* we save the progress on B */
/* etc. */
return 0 ;
}
Это может быть упаковано кодом C ++ для автоматической упаковки resetState./ saveState функции.Например:
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 ;
} ;
, который вы позволяете вам переписать основной как:
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) ;
// etc.
return 0 ;
}
, который выглядит намного лучше, чем версия C.Тем не менее, MyWrapper не является потокобезопасным ...
Заключение
Первое решение (TLS) - это быстрое и грязное решение, а второе - рефакторинг кода для правильной его записи.(есть очень веские причины, по которым глобальные переменные осуждаются, и, по-видимому, вы наткнулись на одну из них), а третий - это «хак», позволяющий вам чередовать два вызова.
Из всех трех решенийтолько вторая позволит легко обернуть этот код в надежные, поточно-ориентированные классы C ++, если это необходимо.