Debugging, statics.
Piercarlo Grandi
pcg at aber-cs.UUCP
Sun Dec 18 03:52:19 AEST 1988
In article <9174 at smoke.BRL.MIL> gwyn at smoke.BRL.MIL (Doug Gwyn ) writes:
[ ... describes problems he had reusing a sort program ... ]
[Side note: Because about 30% of my code was "assert" statements, when
things did go wrong I was able to spot the problem immediately and had
good clues as to the causes.]
Triple Hurrah! This is not a side note, it is a very important thing!
I am a debugger hater. I want to cheer anybody that says that he didn't fire
a debugger to find mistakes, but his code told him/her about them. The best
checks/diagnostics/traces are those that an intelligent programmer puts in
the code, as they are algorithm based. As Knuth wrote "you will find that in
many well written programs half of the code is there to check the other
half".
(The only debugger I use is 'adb' to understand what is going when an
aggressive optimizer sanctified by dpANS C fails to generate correct code...)
The apparent moral is to not use block-scope static initialization, but I
think a better one would be, to design utility programs with the thought
that they should be serially reusable.
I beg to differ, actually to dig deeper into the problem. The moral is that
by using statics (whether local or global) you can only write single instance
generators, and that this single instance is indeed not reusable if you dont'
refresh it.
That way if they ever become subroutines (or repeating slaves like the
one I had) you already have them in shape for the task.
Generators are not subroutines. In most algorithmic languages like C the easy
way to write a generator (a coroutine) is to store its state in
statics/globals. Then you can only have one instance of the generator.
Whenever you fork an executable under Unix a separate instance of its globals
is allocated, and refreshed. You have not used this mechanism for refreshing
the single instance you wanted, because it has high overheads. If you were
using multiple threads (precisely because of their low overhead), you would
not want to use fork for creating multiple instances of it as well.
The real solution would be to have the state of the generator in a struct,
explicitly identified as such. It would then be easy to convert it, as
necessary, from relying on fork() to create new instances and refresh them,
to instead doing it with low overhead program logic, as needed.
In this way one could have as many independent instances of the generator as
you want. Existing examples of this:
[1] struct _iob and all the stdio procedures;
[2] struct u and the Unix system calls.
Yes, struct u is merely a conglobation of the states of all the system calls
of Unix that are generators for a process; when the Mach people wanted to
introduce multiple threads, they had to dynamically allocate a new struct u
per thread, and use a pointer to access the current instance, instead of
addressing it statically.
--
Piercarlo "Peter" Grandi INET: pcg at cs.aber.ac.uk
Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg
UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)
More information about the Comp.lang.c
mailing list