Bit Byte wrote:
I am modifying some legacy code, to make the functions reentrant. I use
lots of global data (large nested structs) to pass data around quicky.
The global structures are far too large (in size) for each of my
functions to maintain copies.
Any suggestions on the best way to write a reentrant version of my
library? - bearing in mind that my global vars are mostly, pointers to
*HUGE* structures.
Others have said there's no re-entrancy in C, but I don't
understand why they think that. A C function running in the
"main line" of the program might also be called from a handler
for an asynchronous signal, and if you want to do this you'll
need to be sure the function is re-entrant. And you can make
it so, with due diligence.
Aside from that limited situation, though, C has no notion
of "concurrent execution," nothing like multiple threads or
parallel processes or anything of that kind. If your problem
involves such beyond-C things then mere re-entrancy alone may
not be enough; you should probably seek advice on a forum like
comp.programmin g.threads.
But to the mechanics: Eliminating the global variables is
not in and of itself enough to make a function re-entrant, but
it's usually a necessary first step. If you've got a global
and a function that manipulates it:
int global;
void set_global(int new_value) {
global = new_value;
}
.... you can get rid of the global by giving the function an
extra argument that points to a non-global substitute:
void set_global(int *global, int new_value) {
*global = new_value;
}
This can become tiresome if there are a lot of globals to
be eliminated, and/or if the functions call each other a lot:
You'll get snarled passing a lot of pointer arguments all over
the place and probably getting some of them wrong. But much
of that can be smoothed over by using a struct:
/* Old */
int global1;
double global2;
char *global3;
void func(void) {
global1 = 42;
global2 = 42.0;
other_func();
}
void other_func(void ) {
global3 = "XLII";
}
/* New */
struct globals {
int global1;
double global2;
char *global3;
};
void func(struct globals *gp) {
gp->global1 = 42;
gp->global2 = 42.0;
other_func(gp);
}
void other_func(stru ct globals *gp) {
gp->global3 = "XLII";
}
If there's a lot of this you may be tempted to use macros
to ease the transition:
struct globals { ... as above ... };
#define global1 gp->global1
#define global2 gp->global2
#define global3 gp->global3
.... which allows you to leave the existing functions almost
unchanged: The source still refers to plain old global2 and
so on, with the pointer automagically inserted. Do this if
you really, really feel you must -- but I've been down that
road, and just a few bends beyond where you can see it gets
rocky and rutted. Better to do the scut-work up front than
to maintain a hack for ever and ever.
--
Eric Sosman
es*****@ieee-dot-org.invalid