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.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: a07f3367d7,8fa1dddecbe9cd04 X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII Path: g2news2.google.com!postnews.google.com!z34g2000vbl.googlegroups.com!not-for-mail From: Ludovic Brenta Newsgroups: comp.lang.ada Subject: Re: How to determine if task is busy or not? Date: Sat, 8 Aug 2009 11:39:11 -0700 (PDT) Organization: http://groups.google.com Message-ID: <288fa06f-bae4-4e60-8b14-79e4bf5a96d5@z34g2000vbl.googlegroups.com> References: <063cfc19-a8fa-41af-b948-d4f8540cb2ab@o36g2000vbl.googlegroups.com> <4aef99b6-6ac6-4e0b-91d8-2a5320ea6e9c@l34g2000vba.googlegroups.com> <11m01goasspup.x63didgf7t0x.dlg@40tude.net> NNTP-Posting-Host: 94.108.252.217 Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Trace: posting.google.com 1249756751 5233 127.0.0.1 (8 Aug 2009 18:39:11 GMT) X-Complaints-To: groups-abuse@google.com NNTP-Posting-Date: Sat, 8 Aug 2009 18:39:11 +0000 (UTC) Complaints-To: groups-abuse@google.com Injection-Info: z34g2000vbl.googlegroups.com; posting-host=94.108.252.217; posting-account=pcLQNgkAAAD9TrXkhkIgiY6-MDtJjIlC User-Agent: G2/1.0 X-HTTP-UserAgent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.11) Gecko/2009061208 Iceweasel/3.0.12 (Debian-3.0.12-1),gzip(gfe),gzip(gfe) Xref: g2news2.google.com comp.lang.ada:7665 Date: 2009-08-08T11:39:11-07:00 List-Id: Dmitry A. Kazakov wrote on comp.lang.ada: > Maciej Sobczak wrote: >> Dmitry A. Kazakov wrote: > >>> The scheme described by Ludovic is not only simpler, it is also race >>> condition free. The reverse scheme has a race condition in it. If you h= ave >>> asked if a task is idle, you do not know if it still is right now > >> Depends. If it is the asking entity that is also providing the job, >> then the problem above cannot happen. In other words, if the "manager" >> asks the task whether it is busy or idle and the answer is "idle", >> then that answer it true until the same manager provides new work >> unit, because there is no other way for the task to switch from "idle" >> to "busy". Which means that the manager can always safely handle a new >> work unit to the "idle" task, no race is possible. > > As I said, only if single job supplier (manager) is here. In that case it > is still a poor scheme because of polling. A better (I tempted to say > proper) one is when idle tasks queue themselves into the pool of idle tas= ks > maintained by the manager. But a protected object of tasks would be bette= r > here as well. > >> The advantage of such a setup is that the manager knows whether the >> work can be handled *immediately* by any one of the tasks in the pool. >> False negatives can be harmless, as long as the positives are >> accurate. > > No, it is not an advantage. > > 1. Job is done to get a result, it is a lengthy process, so there is a > worker to perform it asynchronously. Until the job is done it is of littl= e > interest whether it has been started or not. (Some interest exists if job= s > are cancelable if not initiated) > > 2. The manager is only a mediator here. If a job cannot be started > immediately what the manger is supposed to do? If it does not cancel the > job, the only option is to wait. This is what the job queue is for. > >> Using a queue, as suggested by Ludovic, makes sense only when the work >> units can *wait* for being processed. This might or might not be the >> case. > > See above. If there is some service timeout a queue is serviced by a > monitor task (a special "mister no" worker). Still better. > >> There are examples of systems where either of these schemes are good >> (batch processing vs. real-time?). I would not say that one is better >> than another. > >> To Tomek - the simplest way to deploy your original idea is to use a >> flag (Busy/Idle - an enumeration type is perfect here), which is >> shared and used by both the worker task and its manager. Protected >> object is a proper solution here and you might even use the same >> protected object for managing both the flag and the work unit itself. > > No, you don't need any extra shared data. Do conditional entry call do > determine if the worker is ready: > > task body Worker is > begin > =A0 =A0loop > =A0 =A0 =A0 accept New_Job (Work_Item : in out Job); > =A0 =A0 =A0 ... -- Service > =A0 =A0end loop; > end Worker; > > The manager does a conditional entry call (RM 9.7.3): > > =A0 =A0select > =A0 =A0 =A0 Worker.New_Job (Thing_To_Do); > =A0 =A0else > =A0 =A0 =A0 -- The chap is busy > =A0 =A0 =A0 ... > =A0 =A0end select; But that becomes unwieldy in the presence of multiple worker tasks, any one of which needs to be idle when enqueuing a job. How about: protected Queue is procedure Enqueue (J : in Job); entry Get_Next (J : out Job); private -- left as an exercise :) end Queue; protected body Queue is procedure Enqueue (J : in Job) is begin if Get_Next_Job'Count < 1 then raise No_Worker_Is_Presently_Waiting_For_A_Job; else -- ... end if; end Enqueue; entry Get_Next (J : out Job) when Jobs_Enqueued is begin ... end Get_Next; end Queue; Start all workers before the manager; all workers then start waiting on the Get_Next entry. The manager keeps enqueuing new jobs until all workers are busy, at which point no worker is waiting on Get_Next anymore and the manager gets an exception to signal that condition. Then the difficult part is to ensure that all workers collectively consume jobs at least as fast as the manager can enqueue them. -- Ludovic Brenta.