Path: utzoo!utgpu!watmath!clyde!att!osu-cis!tut.cis.ohio-state.edu!rutgers!gatech!hubcap!ncrcae!ncrlnk!uunet!mcvax!ukc!dcl-cs!aber-cs!pcg From: pcg@aber-cs.UUCP (Piercarlo Grandi) Newsgroups: comp.lang.c Subject: Debugging, statics. Summary: Was 'C Style, continued' statics bite. Generators! Keywords: C style static initialization Message-ID: <421@aber-cs.UUCP> Date: 17 Dec 88 17:52:19 GMT Reply-To: pcg@cs.aber.ac.uk (Piercarlo Grandi) Distribution: eunet,world Organization: CS Dept., University College of Wales, Aberystwyth, UK (Disclaimer: my statements are purely personal) Lines: 63 In article <9174@smoke.BRL.MIL> gwyn@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@cs.aber.ac.uk Sw.Eng. Group, Dept. of Computer Science UUCP: ...!mcvax!ukc!aber-cs!pcg UCW, Penglais, Aberystwyth, WALES SY23 3BZ (UK)