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: ffc1e,fb45e48e8dddeabd X-Google-Attributes: gidffc1e,public X-Google-Thread: 103376,fb45e48e8dddeabd X-Google-Attributes: gid103376,public From: "James S. Rogers" Subject: Re: Ada Protected Object Tutorial #1 Date: 1999/12/16 Message-ID: <83c5t6$k2q$1@bgtnsc03.worldnet.att.net>#1/1 X-Deja-AN: 561774628 References: <839toq$pu$1@bgtnsc03.worldnet.att.net> X-MimeOLE: Produced By Microsoft MimeOLE V4.72.2106.4 X-Complaints-To: abuse@worldnet.att.net X-Trace: bgtnsc03.worldnet.att.net 945396454 20570 12.74.130.185 (17 Dec 1999 02:07:34 GMT) Organization: AT&T WorldNet Services NNTP-Posting-Date: 17 Dec 1999 02:07:34 GMT Newsgroups: comp.programming.threads,comp.lang.ada Date: 1999-12-17T02:07:34+00:00 List-Id: Kaz Kylheku wrote in message ... >On Wed, 15 Dec 1999 22:27:17 -0700, James S. Rogers >What if a protected procedure of an object calls another >protected procedure? Presumably this is allowed, which means that some >recursive lock has to be used for the implementation, or else the compiler has >to generate code that passes around secret ``already locked'' flags into >procedures. What you want is handled by having a protected entry call other protected entries. The "other" protected entries can be in the same protected object or in some other protected object. Protected entries are subject to a very strict queueing policy. When a task calls a protected entry and the boundary condition is closed, the entry call is queued. The calling task will, by default, suspend until the boundary condition opens. Once the boundary condition opens, all the tasks queued on that entry are given access (one at a time) to the entry. No other tasks are allowed to even evaluate the boundary condition until the queue is drained. This approach is intended to allow as much internal progress in a protected object as possible. One of the rules of using a protected entry is that the operations should be very fast, and certainly must not be potentially blocking, such as an I/O read. For providing mutual exclusion for potentially blocking actions you really do want to use some form of a semaphore. >How does the user of the protected object compose atomic operations? > >This approach to design is generally wasteful. It's more reasonable to have >public methods which always lock and unlock, and unprotected methods which >assume that an object is already locked. It's also useful for an object >to expose lock and unlock methods, and expose unprotected operations, so that >the user of the object can compose a sequence of operations into an indivisible >block. Another approach to handling potentially blocking operations is to provide a task whose responsibility is to perform the potentially blocking operation. A protected object can be used to initiate the operation. The requesting task writes a request to the protected object. The servicing task reads the protected object and performs the potentially blocking operation. When the servicing task has completed its operation it can communicate the results to the calling task through a second protected object. This time the servicing task does the writing and the requesting task does the reading. You can look at the protected objects as providing two simplex serial communication paths. Your problem requires fairly complex set of actions to be taken in some atomic manner. The scheme described above combines protected objects with tasks to provide what you need. You can limit the amount of actual task blocking for the above scenario by implementing bounded queues as protected objects. This allows a high degree of asynchronous behavior between the requesting task and the servicing task. >What if you want to block for something in the middle of the critical region? >I assume that you can call a protected entry from within a protected procedure. No, as I stated earlier, you can call a protected entry from another protected entry. >Could you expand on what flexibilities there exist within this framework? This will really be the subject of some future tutorials. I like an involved student! Ada tasking semantics provide several other useful tools beyond protected objects. These include direct synchronizing calls between tasks, known as rendezvous, and various forms of the select statement. A select statement has many uses. One simple example is a select with a delay alternative. This allows you to, for instance, call a protected entry and only wait for a specified duration before giving up and going on to something else. Example: select Buffer.Read(Item); or delay 0.01; -- Delay 0.01 seconds end select; This calls the Read entry on the protected object Buffer. It also starts a timer. If the Read completes before the timer alarms, the timer is aborted. If the timer alarms before the Read completes, the Read is aborted. This gives the programmer very strong control over the timing associated with attempting a protected entry call. You could, for instance, simply loop around and try again in another time slice, or go on to do something else based upon the fact that the Buffer was unavailable. I will be showing more uses of protected objects, tasks, and their interactions in future messages. Jim Rogers Colorado Springs, Colorado