* Re: Activating tasks at Global Scope @ 1993-03-15 14:58 Cheryl Marquis 0 siblings, 0 replies; 6+ messages in thread From: Cheryl Marquis @ 1993-03-15 14:58 UTC (permalink / raw) >The code below implements a producer-consumer system containing one >producing task, two consuming tasks, and a bounded buffer task. I am only >interested in the tasking interactions, so I've omitted the actual buffer >manipulations. This code works fine under the Ada/ED compiler. However, I >would prefer to put the tasks at global scope rather than nest them inside >the producer_consumer procedure. I tried to do this by putting each task >inside a package, but then I couldn't figure out how to activate the tasks >when producer_consumer was invoked. What I'd like is an architecture where >the tasks are automatically started before or at the same time the the main >subprogram is invoked. >If I've done anything particularly gross, feel free to comment >appropriately. Nobody here knows Ada, so I put this together by copying >fairly liberally from Ben-Ari's book, "Principles of Concurrent and >Distributed Programming." >Thanks, >Scott Scott as I see it you have two package options that will allow you a more elegant start up without using delays. They look basically alike the only difference is where the starting up of the task is done. Below is some code that I hope will help you. with Text_IO; use Text_IO; package My_Task_Stuff is task Buffer is --**** This entry provides a means of controlled task -- start ups. Look at body to see how this works entry Start_Up; --**** entry insert(item: in Integer); entry remove(item: out Integer); --**** This entry provides a means of controlled task -- shut downs. Look at body to see how this works entry Shut_Down; --**** end Buffer; task Producer is --**** This entry provides a means of controlled task -- start ups. Look at body to see how this works entry Start_Up; --**** --**** This entry provides a means of controlled task -- shut downs. Look at body to see how this works entry Shut_Down; --**** task Consumer1; --**** This entry provides a means of controlled task -- start ups. Look at body to see how this works entry Start_Up; --**** --**** This entry provides a means of controlled task -- shut downs. Look at body to see how this works entry Shut_Down; --**** task Consumer2; --**** This entry provides a means of controlled task -- start ups. Look at body to see how this works entry Start_Up; --**** --**** This entry provides a means of controlled task -- shut downs. Look at body to see how this works entry Shut_Down; --**** end My_Task_Stuff; package body My_Task_Stuff is task body Buffer is count: Integer := 0; begin --**** put Start up before loop. Task will have to -- wait here until the start up is called. accept Start_Up; -- any initializing can be done here also loop select when count < 10 => accept insert(item: in Integer) do -- insert item into the buffer null; end insert; count := count + 1; or when count > 0 => accept remove(item: out Integer) do -- remove an object from the buffer and assign it to item null; end remove; count := count - 1; or --**** This will give you controlled task exits. You decide -- when the task should end accept Shut_Down; exit; end select; end loop; end Buffer; task body Producer is n: integer; begin --**** put Start up before loop. Task will have to -- wait here until the start up is called. accept Start_Up; -- any initializing can be done here also loop --**** This will give you controlled task exits. You decide -- when the task should end select accept Shut_Down; exit; else -- give n an appropriate value Buffer.insert(n); end select; end loop; end Producer; task body Consumer1 is n: integer; begin --**** put Start up before loop. Task will have to -- wait here until the start up is called. accept Start_Up; -- any initializing can be done here also loop --**** This will give you controlled task exits. You decide -- when the task should end. select accept Shut_Down; exit; else Buffer.remove(n); -- do something with n end select; end loop; end Consumer1; task body Consumer2 is n: integer; begin --**** put Start up before loop. Task will have to -- wait here until the start up is called. accept Start_Up; -- any initializing can be done here also loop --**** This will give you controlled task exits. You decide -- when the task should end select accept Shut_Down; exit; else Buffer.remove(n); -- do something with n end select; end loop; end Consumer2; --**** Now here you have a choice. You can either start these tasks -- in the elaboration area of this package... begin -- My_Task_Stuff Producer.Start_Up; Consumer1.Start_Up; Consumer2.Start_Up; end My_Task_Stuff; with My_Task_Stuff; procedure producer_consumer is begin null; -- will not terminate until all dependent -- tasks terminate end producer_consumer; --**** ... or call the Start_Ups from the main procedure end My_Task_Stuff with My_Task_Stuff; procedure producer_consumer is begin Producer.Start_Up; Consumer1.Start_Up; Consumer2.Start_Up; end producer_consumer; --**** One last thing; you can have procedure calls to your tasks -- and hide the task inside the body instead of having a direct -- task call specified in the Package Spec. I hope I have helped and not confused you too badly. If you have any questions feel free to email me. Cheryl R.S. Marquis cmarquis@unode1.nswc.navy.mil <no clever quote to put here...............YET!> ^ permalink raw reply [flat|nested] 6+ messages in thread
* Activating tasks at global scope @ 1993-03-10 3:32 Scott Meyers 1993-03-10 17:11 ` Robert I. Eachus 1993-03-11 2:51 ` Michael Feldman 0 siblings, 2 replies; 6+ messages in thread From: Scott Meyers @ 1993-03-10 3:32 UTC (permalink / raw) The code below implements a producer-consumer system containing one producing task, two consuming tasks, and a bounded buffer task. I am only interested in the tasking interactions, so I've omitted the actual buffer manipulations. This code works fine under the Ada/ED compiler. However, I would prefer to put the tasks at global scope rather than nest them inside the producer_consumer procedure. I tried to do this by putting each task inside a package, but then I couldn't figure out how to activate the tasks when producer_consumer was invoked. What I'd like is an architecture where the tasks are automatically started before or at the same time the the main subprogram is invoked. If I've done anything particularly gross, feel free to comment appropriately. Nobody here knows Ada, so I put this together by copying fairly liberally from Ben-Ari's book, "Principles of Concurrent and Distributed Programming." Thanks, Scott with Text_IO; use Text_IO; procedure producer_consumer is task Buffer is entry insert(item: in Integer); entry remove(item: out Integer); end Buffer; task body Buffer is count: Integer := 0; begin loop select when count < 10 => accept insert(item: in Integer) do -- insert item into the buffer null; end insert; count := count + 1; or when count > 0 => accept remove(item: out Integer) do -- remove an object from the buffer and assign it to item null; end remove; count := count - 1; end select; end loop; end Buffer; task Producer; task body Producer is n: integer; begin loop -- give n an appropriate value Buffer.insert(n); end loop; end Producer; task Consumer1; task body Consumer1 is n: integer; begin loop Buffer.remove(n); -- do something with n end loop; end Consumer1; task Consumer2; task body Consumer2 is n: integer; begin loop Buffer.remove(n); -- do something with n end loop; end Consumer2; begin null; end; ------------------------------------------------------------------------------- What do you say to a convicted felon in Providence? "Hello, Mr. Mayor." ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Activating tasks at global scope 1993-03-10 3:32 Activating tasks at global scope Scott Meyers @ 1993-03-10 17:11 ` Robert I. Eachus 1993-03-11 3:56 ` Scott Meyers 1993-03-11 2:51 ` Michael Feldman 1 sibling, 1 reply; 6+ messages in thread From: Robert I. Eachus @ 1993-03-10 17:11 UTC (permalink / raw) In article <1993Mar10.033256.24718@cs.brown.edu> sdm@cs.brown.edu (Scott Meyers) writes: > The code below implements a producer-consumer system containing one > producing task, two consuming tasks, and a bounded buffer task. I am only > interested in the tasking interactions, so I've omitted the actual buffer > manipulations. This code works fine under the Ada/ED compiler. However, I > would prefer to put the tasks at global scope rather than nest them inside > the producer_consumer procedure. I tried to do this by putting each task > inside a package, but then I couldn't figure out how to activate the tasks > when producer_consumer was invoked. What I'd like is an architecture where > the tasks are automatically started before or at the same time the the main > subprogram is invoked. You were doing fine, but got bitten by a very subtle feature of Ada. The tasks were all created and elaborated before the main program executed, but then the main program immediately exited. The language reference manual leaves it unspecifed what happens to library tasks in such a situation, but most implementations now terminate them all if they are quiescent. So your tasks disappeared from view before they could act. In any case try hanging your main program, either by putting in a delay statement or by waiting for input...the elegent final version should have a clean way of terminating the program, but this will do for testing. -- Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Activating tasks at global scope 1993-03-10 17:11 ` Robert I. Eachus @ 1993-03-11 3:56 ` Scott Meyers 1993-03-11 17:57 ` Dave Collard x7468 0 siblings, 1 reply; 6+ messages in thread From: Scott Meyers @ 1993-03-11 3:56 UTC (permalink / raw) In article <EACHUS.93Mar10121115@goldfinger.mitre.org> eachus@goldfinger.mitre.org (Robert I. Eachus) writes: | You were doing fine, but got bitten by a very subtle feature of Ada. | The tasks were all created and elaborated before the main program | executed, but then the main program immediately exited. The language | reference manual leaves it unspecifed what happens to library tasks in | such a situation, but most implementations now terminate them all if | they are quiescent. So your tasks disappeared from view before they | could act. | | In any case try hanging your main program, either by putting in a | delay statement or by waiting for input...the elegent final version | should have a clean way of terminating the program, but this will do | for testing. I tried to follow this advice, but none of the tasks appears to run; certainly the output statements in their initialization blocks are never executed. I've appended the full program below, and I'd appreciate it if somebody could help me figure out what's wrong. Trust me when I tell you I've tried to solve this problem myself. (I had quite a lovely time determining that the behavior of the Ada/Ed compiler is dependent in part on the name of the file containing the source, and I don't mean the file extensions. In particular, the compiler generates an internal error on a whole host of file names. Names containing numbers seem to be particularly offensive to it...) Thanks for your help, Scott with Text_IO; use Text_IO; package Buffer_Package is task Buffer is entry insert(item: in Integer); entry remove(item: out Integer); end Buffer; end Buffer_Package; package body Buffer_Package is task body Buffer is count: Integer := 0; begin loop select when count < 10 => accept insert(item: in Integer) do -- insert item into the buffer PUT_LINE("ACCEPTING AN INSERTION"); null; end insert; count := count + 1; or when count > 0 => accept remove(item: out Integer) do -- remove an object from the buffer and assign it to item PUT_LINE("ACCEPTING A REMOVAL"); null; end remove; count := count - 1; end select; end loop; end Buffer; begin PUT_LINE("STARTING BUFFER_PACKAGE"); end Buffer_Package; -------------------------------------------------------------------------- with Text_IO; use Text_IO; with Buffer_Package; use Buffer_Package; package Producer_Package is task Producer; end Producer_Package; package body Producer_Package is task body Producer is n: integer; begin loop -- give n an appropriate value PUT_LINE("INSERTING"); Buffer.insert(n); end loop; end Producer; begin PUT_LINE("STARTING PRODUCER_PACKAGE"); end Producer_Package; -------------------------------------------------------------------------- with Text_IO; use Text_IO; with Buffer_Package; use Buffer_Package; package Consumer1_Package is task Consumer1; end Consumer1_Package; package body Consumer1_Package is task body Consumer1 is n: integer; begin loop PUT_LINE("REMOVING2"); Buffer.remove(n); -- do something with n end loop; end Consumer1; begin PUT_LINE("STARTING CONSUMER1_PACKAGE"); end Consumer1_Package; -------------------------------------------------------------------------- with Text_IO; use Text_IO; with Buffer_Package; use Buffer_Package; package Consumer2_Package is task Consumer2; end Consumer2_Package; package body Consumer2_Package is task body Consumer2 is n: integer; begin loop PUT_LINE("REMOVING2"); Buffer.remove(n); -- do something with n end loop; end Consumer2; begin PUT_LINE("STARTING CONSUMER2_PACKAGE"); end Consumer2_Package; -------------------------------------------------------------------------- with Text_IO; use Text_IO; procedure producer_consumer is begin PUT_LINE("STARING DELAY..."); delay 5.0; PUT_LINE("DONE."); end producer_consumer; ------------------------------------------------------------------------------- What do you say to a convicted felon in Providence? "Hello, Mr. Mayor." ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Activating tasks at global scope 1993-03-11 3:56 ` Scott Meyers @ 1993-03-11 17:57 ` Dave Collard x7468 0 siblings, 0 replies; 6+ messages in thread From: Dave Collard x7468 @ 1993-03-11 17:57 UTC (permalink / raw) >with Text_IO; >use Text_IO; >package Buffer_Package is ... >end Buffer_Package; >package body Buffer_Package is > task body Buffer is > end Buffer; > >begin > PUT_LINE("STARTING BUFFER_PACKAGE"); >end Buffer_Package; >with Text_IO; >use Text_IO; >with Buffer_Package; >use Buffer_Package; >package Producer_Package is > task Producer; >end Producer_Package; >package body Producer_Package is > task body Producer is > end Producer; >begin > PUT_LINE("STARTING PRODUCER_PACKAGE"); >end Producer_Package; >with Text_IO; >use Text_IO; >with Buffer_Package; >use Buffer_Package; >package Consumer1_Package is > task Consumer1; >end Consumer1_Package; >package body Consumer1_Package is > task body Consumer1 is > end Consumer1; >begin > PUT_LINE("STARTING CONSUMER1_PACKAGE"); >end Consumer1_Package; >with Text_IO; >use Text_IO; >with Buffer_Package; >use Buffer_Package; >package Consumer2_Package is > task Consumer2; >end Consumer2_Package; >package body Consumer2_Package is > task body Consumer2 is > end Consumer2; >begin > PUT_LINE("STARTING CONSUMER2_PACKAGE"); >end Consumer2_Package; >with Text_IO; >use Text_IO; -- Perhaps you need to add a few with statements here! When -- you link producer_consumer, the only thing you are linking -- with is Text_IO! Try adding: with Buffer_Package; with Producer_Package; with Consumer1_Package; with Consumer2_Package; >procedure producer_consumer is >begin > PUT_LINE("STARING DELAY..."); > delay 5.0; > PUT_LINE("DONE."); >end producer_consumer; --Thor dlc@ddsdx2.jhuapl.edu collard@capsrv.jhuapl.edu ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: Activating tasks at global scope 1993-03-10 3:32 Activating tasks at global scope Scott Meyers 1993-03-10 17:11 ` Robert I. Eachus @ 1993-03-11 2:51 ` Michael Feldman 1 sibling, 0 replies; 6+ messages in thread From: Michael Feldman @ 1993-03-11 2:51 UTC (permalink / raw) In article <1993Mar10.033256.24718@cs.brown.edu> sdm@cs.brown.edu (Scott Meyers) writes: >The code below implements a producer-consumer system containing one >producing task, two consuming tasks, and a bounded buffer task. I am only >interested in the tasking interactions, so I've omitted the actual buffer >manipulations. This code works fine under the Ada/ED compiler. However, I >would prefer to put the tasks at global scope rather than nest them inside >the producer_consumer procedure. I tried to do this by putting each task >inside a package, but then I couldn't figure out how to activate the tasks >when producer_consumer was invoked. What I'd like is an architecture where >the tasks are automatically started before or at the same time the the main >subprogram is invoked. > Put the tasks in a package. Attached is a comparable example, though a bit more involved than yours. It's a re-post of my Portable Diners Kit, which is now being distributed as one of the Ada/Ed demos, and also appears in the Ada Quality & Style Guide. Have a look and have fun. The various compilation units can be separated or left in one file; they appear in a correct compilation order, so one compiler invocation will do it. Link and run "diners". Mike Feldman ---- cut here ---- --:::::::::: --io_libs.ada --:::::::::: -- Precompiled instantiations of Integer_IO and -- Float_IO for the predefined Integer and Float types WITH Text_IO; PACKAGE My_Int_IO IS NEW Text_IO.Integer_IO (Num => Integer); WITH Text_IO; PACKAGE My_Flt_IO IS NEW Text_IO.Float_IO (Num => Float); --:::::::::: --random.ads --:::::::::: PACKAGE Random IS -- Simple pseudo-random number generator package. -- Adapated from the Ada literature by -- Michael B. Feldman, The George Washington University, November 1990. PROCEDURE Set_Seed (N : Positive); FUNCTION Unit_Random RETURN Float; --returns a float >=0.0 and <1.0 FUNCTION Random_Int (N : Positive) RETURN Positive; --return a random integer in the range 1..N END Random; --:::::::::: --chop.ads --:::::::::: PACKAGE Chop IS TASK TYPE Stick IS ENTRY Pick_Up; ENTRY Put_Down; END Stick; END Chop; --:::::::::: --phil.ads --:::::::::: PACKAGE Phil IS TASK TYPE Philosopher IS ENTRY Come_To_Life (My_ID : Positive; Chopstick1 : Positive; Chopstick2 : Positive); END Philosopher; TYPE States IS (Breathing, Thinking, Eating, Done_Eating, Got_One_Stick, Got_Other_Stick); END Phil; --:::::::::: --room.ads --:::::::::: WITH Chop; WITH Phil; PACKAGE Room IS Table_Size: CONSTANT := 5; SUBTYPE Table_Type IS Positive RANGE 1..Table_Size; Sticks: ARRAY(Table_Type) OF Chop.Stick; TASK Head_Waiter IS ENTRY Open_The_Room; ENTRY Report_State(Which_Phil: Table_Type; State: Phil.States; How_Long: Natural := 0); END Head_Waiter; END Room; --:::::::::: --diners.ada --:::::::::: WITH Room; PROCEDURE Diners IS BEGIN Room.Head_Waiter.Open_The_Room; LOOP DELAY 20.0; END LOOP; END Diners; --:::::::::: --random.adb --:::::::::: WITH Calendar; USE Calendar; PACKAGE BODY Random IS -- Body of random number generator package. -- Adapted from the Ada literature by -- Michael B. Feldman, The George Washington University, November 1990. Modulus : CONSTANT := 9317; TYPE Int_16 IS RANGE - 2 ** 15 .. 2 ** 15 - 1; TYPE Int_32 IS RANGE - 2 ** 31 .. 2 ** 31 - 1; SUBTYPE Seed_Range IS Int_16 RANGE 0 .. (Modulus - 1); Seed, Default_Seed : Seed_Range; PROCEDURE Set_Seed (N : Positive) IS SEPARATE; FUNCTION Unit_Random RETURN Float IS SEPARATE; FUNCTION Random_Int (N : Positive) RETURN Positive IS SEPARATE; BEGIN Default_Seed := Int_16 (Int_32 (Seconds (Clock)) MOD Modulus); Seed := Default_Seed; END Random; SEPARATE (Random) PROCEDURE Set_Seed (N : Positive) IS BEGIN Seed := Seed_Range (N); END Set_Seed; SEPARATE (Random) FUNCTION Unit_Random RETURN Float IS Multiplier : CONSTANT := 421; Increment : CONSTANT := 2073; Result : Float; BEGIN Seed := (Multiplier * Seed + Increment) MOD Modulus; Result := Float (Seed) / Float (Modulus); RETURN Result; EXCEPTION WHEN Constraint_Error | Numeric_Error => Seed := Int_16 ((Multiplier * Int_32 (Seed) + Increment) MOD Modulus); Result := Float (Seed) / Float (Modulus); RETURN Result; END Unit_Random; SEPARATE (Random) FUNCTION Random_Int (N : Positive) RETURN Positive IS Result : Integer RANGE 1 .. N; BEGIN Result := Integer (Float (N) * Unit_Random + 0.5); RETURN Result; EXCEPTION WHEN Constraint_Error | Numeric_Error => RETURN 1; END Random_Int; --:::::::::: --chop.adb --:::::::::: PACKAGE BODY Chop IS TASK BODY Stick IS BEGIN LOOP SELECT ACCEPT Pick_Up; ACCEPT Put_Down; OR TERMINATE; END SELECT; END LOOP; END Stick; END Chop; --:::::::::: --phil.adb --:::::::::: WITH Room; WITH Random; PACKAGE BODY Phil IS TASK BODY Philosopher IS Who_Am_I : Positive; First_Grab : Positive; Second_Grab: Positive; Meal_Time : Natural; Think_Time : Natural; BEGIN ACCEPT Come_To_Life (My_ID : Positive; Chopstick1 : Positive; Chopstick2 : Positive) DO Who_Am_I := My_ID; First_Grab := Chopstick1; Second_Grab := Chopstick2; END Come_To_Life; Room.Head_Waiter.Report_State(Who_Am_I, Breathing); LOOP Room.Sticks(First_Grab).Pick_Up; Room.Head_Waiter.Report_State(Who_Am_I, Got_One_Stick, First_Grab); Room.Sticks(Second_Grab).Pick_Up; Room.Head_Waiter.Report_State(Who_Am_I, Got_Other_Stick, Second_Grab); Meal_Time := Random.Random_Int(10); Room.Head_Waiter.Report_State(Who_Am_I, Eating, Meal_Time); DELAY Duration(Meal_Time); Room.Head_Waiter.Report_State(Who_Am_I, Done_Eating); Room.Sticks(First_Grab).Put_Down; Room.Sticks(Second_Grab).Put_Down; Think_Time := Random.Random_Int(10); Room.Head_Waiter.Report_State(Who_Am_I, Thinking, Think_Time); DELAY Duration(Think_Time); END LOOP; END Philosopher; END Phil; --:::::::::: --roomline.adb --:::::::::: WITH Text_IO; WITH Chop; WITH Phil; WITH Calendar; PRAGMA Elaborate(Phil); PACKAGE BODY Room IS -- A line-oriented version of the Room package, for line-oriented -- terminals like IBM 3270's where the user cannot do ASCII screen control. -- This is the only file in the dining philosophers system that needs -- changing to use in a line-oriented environment. -- Michael B. Feldman, The George Washington University, November 1990. Phils: ARRAY(Table_Type) OF Phil.Philosopher; TYPE Phil_Names IS (Dijkstra, Texel, Booch, Ichbiah, Stroustrup); TASK BODY Head_Waiter IS T : Integer; Start_Time: Calendar.Time; Phil_Names: CONSTANT ARRAY(1..5) OF String(1..18) := ("Eddy Dijkstra ", "Putnam Texel ", "Grady Booch ", "Jean Ichbiah ", "Bjarne Stroustrup "); Blanks : CONSTANT String := " "; BEGIN ACCEPT Open_The_Room; Start_Time := Calendar.Clock; Phils(1).Come_To_Life(1,1,2); Phils(3).Come_To_Life(3,3,4); Phils(2).Come_To_Life(2,2,3); Phils(5).Come_To_Life(5,1,5); Phils(4).Come_To_Life(4,4,5); LOOP SELECT ACCEPT Report_State(Which_Phil: Table_Type; State: Phil.States; How_Long: Natural := 0) DO T := Integer(Calendar."-"(Calendar.Clock,Start_Time)); Text_IO.Put( "T=" & Integer'Image(T) & " " & Blanks(1..Which_Phil) & Phil_Names(Which_Phil)); CASE State IS WHEN Phil.Breathing => Text_IO.Put("Breathing"); WHEN Phil.Thinking => Text_IO.Put( "Thinking" & Integer'Image(How_Long) & " seconds."); WHEN Phil.Eating => Text_IO.Put( "Eating" & Integer'Image(How_Long) & " seconds."); WHEN Phil.Done_Eating => Text_IO.Put("Yum-yum (burp)"); WHEN Phil.Got_One_Stick => Text_IO.Put( "First chopstick" & Integer'Image(How_Long)); WHEN Phil.Got_Other_Stick => Text_IO.Put( "Second chopstick" & Integer'Image(How_Long)); END CASE; Text_IO.New_Line; END Report_State; OR TERMINATE; END SELECT; END LOOP; END Head_Waiter; END Room; ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~1993-03-15 14:58 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 1993-03-15 14:58 Activating tasks at Global Scope Cheryl Marquis -- strict thread matches above, loose matches on Subject: below -- 1993-03-10 3:32 Activating tasks at global scope Scott Meyers 1993-03-10 17:11 ` Robert I. Eachus 1993-03-11 3:56 ` Scott Meyers 1993-03-11 17:57 ` Dave Collard x7468 1993-03-11 2:51 ` Michael Feldman
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox