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=0.2 required=5.0 tests=BAYES_00,INVALID_MSGID, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,1583af5ff29435e5,start X-Google-Attributes: gid103376,public From: Florian Weimer Subject: Dynamic allocation of tasks Date: 2000/03/22 Message-ID: <87r9d3gvix.fsf@deneb.cygnus.argh.org>#1/1 X-Deja-AN: 600796236 Mail-Copies-To: never Content-Type: text/plain; charset=us-ascii X-Complaints-To: abuse@cygnus.argh.org X-Trace: deneb.cygnus.argh.org 953720166 12877 192.168.1.2 (22 Mar 2000 10:16:06 GMT) Organization: Penguin on board User-Agent: Gnus/5.0804 (Gnus v5.8.4) Emacs/20.6 Mime-Version: 1.0 Reply-To: Florian Weimer NNTP-Posting-Date: 22 Mar 2000 10:16:06 GMT Newsgroups: comp.lang.ada Date: 2000-03-22T10:16:06+00:00 List-Id: Dynamically allocating tasks isn't really a problem, but deallocating them is. :-/ I found no way to complete a task before its allocator completes. Most of the time, this is a good thing. But if you are allocating tasks using an allocator for a library-level access type, you'll almost certainly run into problems, because these tasks won't complete until the program terminates. There are workarounds, of course, and I'll describe two of them below. If you know different ones, I'd be glad if you could share them; I'm going to add a summary to the FAQ at www.adapower.com (if David Botton agrees). First Solution: Static allocation This solution uses an approach comparable to a typical implementation of Ada.Strings.Bounded. Of course, this simple solution isn't possible in all cases. Code example: task type Some_Task; type Task_Array is array (Positive range <>) of Some_Task; type Dynamic_Tasks_Type (Number_Of_Tasks : Natural) is record Tasks : Task_Array (1 .. Number_Of_Tasks); Last_Allocated_Task : Natural := 0; -- an index into Tasks end record; Some_Task typically has got some kind of start entry, so that superfluous elements in Tasks which aren't really used cause no harm (besides unnecessary resource consumption). This approach gets more and more clumsy if you've got more than one task type because you have to specify each task count individually. Second Solution: Localize the access type used to allocate tasks The idea behind this is that an access type which is declared locally doesn't cause the problems of a library-level one. This is not always directly possible, e.g. in the following pseudocode (which uses a hypothetical package Dynamic_Tasks which allocates tasks dynamically): Dynamic_Tasks.Allocates_Tasks_As_Side_Effect; Dynamic_Tasks.Allocates_More_Tasks_As_Side_Effect; Dynamic_Tasks.Do_Something_With_These_Tasks; Dynamic_Tasks.Do_Something_Else; Dynamic_Tasks.Wait_For_These_Tasks; All these functions must access the allocated tasks, and they have to use an access of a type declared in the enclosing package for that. Usually, this access type is located at the library level, but if you make the package a generic one, this is no longer the case. The drawback of this solution: It might result in severe code bloat if the compiler doesn't support shared generics. In order to avoid this code bloat, one could declare in a generic subprogram the access type whose allocator is used to allocate the tasks. The operations listed in the example would be placed into a local subprogram, and this subprogram would be passed as actual parameter to the generic subprogram instantiation.