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.8 required=5.0 tests=BAYES_00,INVALID_DATE, MSGID_SHORT autolearn=no autolearn_force=no version=3.4.4 Xref: utzoo comp.sw.components:444 comp.lang.ada:3553 comp.sys.encore:559 Path: utzoo!attcan!uunet!samsung!zaphod.mps.ohio-state.edu!usc!rutgers!umn-d-ub!kpierce From: kpierce@umn-d-ub.D.UMN.EDU (Keith Pierce) Newsgroups: comp.sw.components,comp.lang.ada,comp.sys.encore Subject: Strange behavior by Ada tasks Keywords: ada, task, semaphore, concurrent, component Message-ID: <3295@umn-d-ub.D.UMN.EDU> Date: 27 Mar 90 17:57:00 GMT Organization: U of Minnesota-Duluth, Information Services List-Id: I am developing software components a la Grady Booch (SOFTWARE COMPONENTS WITH ADA, Benjamin Cummings 1987), but am having trouble with the concurrent version of queues. Booch uses semaphores hidden in the structure to guarantee that only one task at a time is actively processing a queue. However, when I activate several tasks to simultaneously update a queue, strange results ensue. I appeal to experts in Ada tasking and/or Booch components to help me determine whether it's my fault or the compilers (I am using Verdix Ada, as ported to Encore Multimax, a multiprocessor Unix machine, and thus supports true concurrency). To simplify your task, I have written a simple version of my original program, that uses semaphores to protect an integer variable from simultaneous update. The program defines a package that defines a protected natural variable type and a single operation that adds one to the variable. The main program defines two tasks that simultaneously try to update the variable each 10 times. If correctly working, the variable's value at the end should be 20, but it ends up being 10. Here are the pieces of the program. Each piece delimited by dashes resides in a separate file. --------------------------------------------------------------- -- Specification of Semaphores -- Reference: Booch --------------------------------------------------------------- package Semaphore is type Kind is limited private; procedure Seize (The_Semaphore : in Kind); procedure Release (The_Semaphore : in Kind); private task type Kind is entry Seize; entry Release; end Kind; end Semaphore; ---------------------------------------------------------------- -- Body of semaphore package. -- Reference: Booch ---------------------------------------------------------------- package body Semaphore is task body Kind is In_Use : Boolean := False; begin loop select when not In_Use => accept Seize; In_Use := True; or when In_Use => accept Release; In_Use := False; or terminate; end select; end loop; end Kind; procedure Seize (The_Semaphore : in Kind) is begin The_Semaphore.Seize; end Seize; procedure Release (The_Semaphore : in Kind) is begin The_Semaphore.Release; end Release; end Semaphore; -------------------------------------------------------------- -- Specification of package Nat_Package -- Defines an abstract type of object "Protected_Natural" -- Objects declared of this type have initial value zero. -- Operaton "Add_One" increments the object by one. -- Operation "Put" outputs the value to standard output -- Semaphores are used to protect against simultaneous access -------------------------------------------------------------- with Semaphore; package Nat_Package is type Protected_Natural is limited private; procedure Add_One (To_Number : in out Protected_Natural); procedure Put (The_Number : in Protected_Natural); private type Protected_Natural is record The_Value : Natural := 0; Guard : Semaphore.Kind; end record; end Nat_Package; -------------------------------------------------------------- -- Body of package Nat_Package. -------------------------------------------------------------- with Semaphore; with Text_Io; use Text_Io; package body Nat_Package is package Natural_Io is new Text_Io.Integer_Io(Natural); use Natural_Io; procedure Add_One (To_Number : in out Protected_Natural) is begin Semaphore.Seize (To_Number.Guard); To_Number.The_Value := To_Number.The_Value + 1; Put("Adding one, new value is"); Put (To_Number.The_Value, width => 1); New_Line; Semaphore.Release (To_Number.Guard); end Add_One; procedure Put (The_Number : in Protected_Natural) is begin Natural_Io.Put (The_Number.The_Value, width => 1); end Put; end Nat_Package; ------------------------------------------------------------ -- Main program Par_Test -- Declares a global object of type Protected_Natural -- and two tasks, Add1 and Add2, that, when activated by -- calling entry Start, each add one to Counter 10 times. -- When done (as signaled by "Signal_Done" rendesvous with -- main program), main program prints the final value. -- It should be 20, but is 10. ----------------------------------------------------------- with Text_io, Nat_Package; use Text_Io; use Nat_Package; procedure Par_Test is package Natural_Io is new Integer_Io(Natural); use Natural_Io; task type Adder is entry Start (How_Many : in Natural); entry Signal_Done; end Adder; Counter : Protected_Natural; Add1, Add2 : Adder; -- Note that task body accesses Counter globally task body Adder is Limit : Natural; begin accept Start(How_Many : in Natural) do Limit := How_Many; end Start; for Index in 1..Limit loop Nat_Package.Add_One (To_Number => Counter); end loop; accept Signal_Done; end Adder; begin Add1.Start(10); Add2.Start(10); Add1.Signal_Done; Add2.Signal_Done; Put ("The final value of Counter is "); Nat_Package.Put (Counter); end Par_test; -------------------------------------------------------------- -------------------------------------------------------------- -- Here is a script of the output of this program. -------------------------------------------------------------- -------------------------------------------------------------- Adding one, new value is1 Adding one, new value is1 Adding one, new value is2 Adding one, new value is2 Adding one, new value is3 Adding one, new value is3 Adding one, new value is4 Adding one, new value is4 Adding one, new value is5 Adding one, new value is5 Adding one, new value is6 Adding one, new value is6 Adding one, new value is7 Adding one, new value is7 Adding one, new value is8 Adding one, new value is8 Adding one, new value is9 Adding one, new value is9 Adding one, new value is10 Adding one, new value is10 The final value of Counter is 10