From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,73bdb823e1c1f689 X-Google-Attributes: gid103376,public From: mheaney@ni.net (Matthew Heaney) Subject: Re: idiom for task termination? Date: 1997/02/08 Message-ID: #1/1 X-Deja-AN: 217537455 references: <32FA10EF.32A@bix.com> content-type: text/plain; charset=ISO-8859-1 organization: Estormza Software mime-version: 1.0 newsgroups: comp.lang.ada Date: 1997-02-08T00:00:00+00:00 List-Id: In article <32FA10EF.32A@bix.com>, tmoran@bix.com wrote: >What's a good idiom for terminating tasks inside library packages? >If I build a re-usable package which contains an internal task which >has an 'entry quit' but does not have a select-terminate alternative, >I want to guarantee that it does in fact terminate even if the user's >main program fails to call 'quit' (eg, dies on an unhandled exception). There's no such thing as "main program fails to call quit." Stop playing these "what if" games: you either build a correct, working system, or you don't. Bertrand Meyer popularized the concept of "programming by contract." An abstraction provides a service by stating what it guarantees will happen, provided that the client guarantees he'll do what the abstraction requires. An abstraction states that there is a certain protocol that must be followed for everything to work as advertised. In particular, this supplier doesn't have anything to say about what will happen if the client fails to obey that protocol. This is the only way to build large systems: everyone does their job, without worrying about whether other components break the rules. Just build the system right, so no rules are broken. A simple example is that often library-level packages contain an Initialize method. The abstraction requires that the Initiailze method be called in order for the other operations to work. It does not worry about whether Initialize gets called; it has to be called. It not, then there's an error in some other part of the sytem, so fix that. So don't bother trying to guarantee that you can still quit if your client doesn't tell you to quit. Are you required to be told to quit, or not? A common idiom with tasks is to have Start_Up and Shut_Down alternatives. This gives the application the ability to do some initialization and finalization, such as opening and closing a device. It looks like this package P is procedure Initialize (...); procedure Finalize; ... end; package body P is task T is entry Start_Up (...); entry Shut_Down; entry E1; ... end; procedure Initialize (...) is begin T.Start_Up (...); end; procedure Finalize is begin T.Shut_Down; end; task T is begin select accept Start_Up (...) do ... end Start_Up; or terminate; end select; Main: loop select accept Shut_Down do ... end; exit Main; or accept E1; ... end select; end loop Main; end T; end P; The protocol is as follows: If you don't call Initialize, then you must not call Finalize. And I guarantee that I'll terminate. If you do call Initialize, then you must call Finalize too. And I'll guarantee that I'll terminate. Task T doesn't worry about Shut_Down being called, without Start_Up already having been called. Nor does it worry about Start_Up being called again, once it's already been called. Nor does it worry about Shut_Down not being called, once Start_Up has been called. If you need to be told to quit, then that's what you require to terminate. Period. If the client fails to call quit, then it has the error, so spend your time fixing that, instead of worrying about all these "what happens if..." scenarios. -------------------------------------------------------------------- Matthew Heaney Software Development Consultant (818) 985-1271