Prev: Newbie question: How to use gnat make
Next: Performance of access type : a tiny mistake in the WikiBook ?
From: Dmitry A. Kazakov on 25 Sep 2009 06:31 On Fri, 25 Sep 2009 02:57:42 -0700 (PDT), Ludovic Brenta wrote: > Dmitry A. Kazakov wrote on comp.lang.ada: >> Timing_Events does not have any advantages over delay or asynchronous >> transfer of control. I guess it was provided for some low-level stuff like >> interrupts from hardware timers. However there was already a support for >> interrupts mapped into protected operations, so it really puzzles me why >> Timing_Events were added. > > The reasons are explained in AI95-297. It seems you've never written > any low-level code before, or cared about it? .... cared not to write lower-level code. (:-)) > [1] http://www.ada-auth.org/cgi-bin/cvsweb.cgi/ais/ai-00297.txt?rev=1.25 The example of changing task priorities looks artificial to me. I don't think a "normal" concurrent applications could benefit from Timing_Events. There were much more pressing problems than this one (making tasks and protected objects tagged, working task components of controlled objects etc.) -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: Jean-Pierre Rosen on 25 Sep 2009 07:23 Dmitry A. Kazakov a �crit : > Timing_Events does not have any advantages over delay or asynchronous > transfer of control. I guess it was provided for some low-level stuff like > interrupts from hardware timers. However there was already a support for > interrupts mapped into protected operations, so it really puzzles me why > Timing_Events were added. > The answer is easy: because users asked for it. Of course, it is useless, but some people don't feel easy with tasks, and want to use the kind of tools they are accustomed to. So rather than painfully answering requests like "why doesn't Ada have that feature", it was simpler to say "what's the heck" and provide it. If you don't like it (I am also in that case), don't use it. -- --------------------------------------------------------- J-P. Rosen (rosen(a)adalog.fr) Visit Adalog's web site at http://www.adalog.fr
From: John B. Matthews on 25 Sep 2009 11:56 In article <h9g8mf$v4f$1(a)news.eternal-september.org>, Reto Buerki <reet(a)codelabs.ch> wrote: > The test code below implements a simple alarm clock which should > wakeup the task waiting on the "Wait_For_Wakeup" entry. > > With GNAT 4.3.2 on Debian/stable this does not work. The main task > remains queued on the entry even though the Wakeup-handler is invoked > correctly by the Timing_Event. > > Compiling the same code with GNAT 4.4.1-5 (on Debian/SID) or GNAT GPL > 2009 leads to the expected behavior: The main task terminates after > the alarm has fired. This indicates a bug in FSF GNAT 4.3.2. I get the same result with FSF GNAT 4.3.4. I revised your code to follow the "protected Event" example seen here: <http://www.adaic.com/standards/95rat/RAThtml/rat95-p1-2.html#9> It seems to work. The compiler warns, "potentially blocking operation in protected operation" in Wakeup, although the Signal barrier is always true. I'm not sure the extra entries _should_ be required, but I think it might be more reliable in the face of multiple threads calling Wait. I don't know a reason why it wouldn't work under 4.3.2. with Ada.Text_IO; with Alarm_Clock; procedure Main is My_Alarm : Alarm_Clock.Alarm_Type; begin Ada.Text_IO.Put_Line ("Starting alarm ..."); My_Alarm.Start; Ada.Text_IO.Put_Line ("Waiting for alarm ..."); My_Alarm.Wait; Ada.Text_IO.Put_Line ("ALARM!!"); end Main; package Alarm_Clock is use Ada.Real_Time; protected type Alarm_Type is entry Wait; entry Signal; procedure Start; procedure Wakeup(Event : in out Timing_Events.Timing_Event); private entry Reset; Alarm : Boolean := False; end Alarm_Type; end Alarm_Clock; package body Alarm_Clock is Timer : Timing_Events.Timing_Event; protected body Alarm_Type is procedure Start is begin Timer.Set_Handler(In_Time => Seconds (1), Handler => Wakeup'Access); end Start; procedure Wakeup(Event : in out Timing_Events.Timing_Event) is begin Alarm := True; Signal; end Wakeup; entry Wait when Alarm is begin null; end Wait; entry Signal when True is begin if Wait'Count > 0 then Alarm := True; requeue Reset; end if; end Signal; entry Reset when Wait'Count = 0 is begin Alarm := False; end Reset; end Alarm_Type; end Alarm_Clock; -- John B. Matthews trashgod at gmail dot com <http://sites.google.com/site/drjohnbmatthews>
From: Brad Moore on 25 Sep 2009 13:06 Dmitry A. Kazakov wrote: > You must do it per a monitor task anyway. Your design is not scalable, and > the code is not conformant to Ada, because you are using potentially > blocking Put_Line within a protected action (in Call_Police). > > When an alarm is triggered, that happens at the context of a protected > action. The protected action is quite limited to what you could do there. > That is only non-blocking and *very* short stuff. This means that you won't > be able to "call police" from there. You could set some flags, but you > could not initiate any "non-instant" action otherwise than by releasing a > task. Non-instant actions are for tasks. You need a task. If the key input > task gets blocked beyond reach of asynchronous transfer of control, which > is your case, because Ada does not require Text_IO abortable (yet > misleadingly provides an example of in RM (:-)), anyway, that means, you > inescapably need a second task. A real implementation of Call_Police would hopefully have more effect then just printing a message to a console. Yes, Text_IO.Put_Line is potentially blocking and clouds the example, thanks for catching that. Conceivably though, it may be possible to use some other console output that is non-blocking if Call_Police really does need to log something to a console. Also, Call_Police does not necessarily need to involve a task. For example, it may simply raise a signal on some hardware device that calls 911, or turns on a siren, or flashing lights or whatever. Even if it does perform some protected operation that kicks off another task, the timing event approach might hold appeal to some, or be more of an appropriate design choice, though in that case, I would probably recommend at least considering some other approach such as the use a timed/conditional entry call. Timing_Events should handle a reasonable number of events in the system. If your application has millions of these firing all over the place, then scalability could become an issue, and perhaps for such a system, some alternate design would be more appropriate. > > ----------- > Timing_Events does not have any advantages over delay or asynchronous > transfer of control. I guess it was provided for some low-level stuff like > interrupts from hardware timers. However there was already a support for > interrupts mapped into protected operations, so it really puzzles me why > Timing_Events were added. > I see timing events as being potentially useful reusable concurrency component. If you ever need something that looks like timing_events, then hopefully it will save you from having to write your own. It may have utility in some areas such as discrete event simulation, for example, if you need something to coordinate multiple tasks and ensure that signalling events occur and run to completion before before signaling subsequent events. Whether timing_events is something that will be used a lot in practice is another question. I worked on a legacy system (written in Ada 83) that had a package very similar to timing_events. It was used to trigger timeouts in a run-to-completion tasking model. In that environment, the creation of tasks was discouraged, and only allowed if absolutely necessary. This timing_events package provided a convenient way to coordinate the existing tasks and trigger things to happen in the future without having to introduce more tasks in the system. Of course, as with the standard timing_package, timing events need to be non-blocking and fast. Had the standard timing package existed at that time, we probably would have used that instead. If I were building the system again from scratch, though, maybe I wouldn't use timing_events at all. I suspect that some people will find timing_events to be useful for specific types of applications, but probably will not be used on any grand scale. I think mostly people should/will want to use other existing synchronization mechanisms in Ada to coordinate tasks. Brad
From: Dmitry A. Kazakov on 25 Sep 2009 14:42
On Fri, 25 Sep 2009 11:06:05 -0600, Brad Moore wrote: > Dmitry A. Kazakov wrote: >> You must do it per a monitor task anyway. Your design is not scalable, and >> the code is not conformant to Ada, because you are using potentially >> blocking Put_Line within a protected action (in Call_Police). >> >> When an alarm is triggered, that happens at the context of a protected >> action. The protected action is quite limited to what you could do there. >> That is only non-blocking and *very* short stuff. This means that you won't >> be able to "call police" from there. You could set some flags, but you >> could not initiate any "non-instant" action otherwise than by releasing a >> task. Non-instant actions are for tasks. You need a task. If the key input >> task gets blocked beyond reach of asynchronous transfer of control, which >> is your case, because Ada does not require Text_IO abortable (yet >> misleadingly provides an example of in RM (:-)), anyway, that means, you >> inescapably need a second task. > > A real implementation of Call_Police would hopefully have more effect > then just printing a message to a console. Yes, Text_IO.Put_Line is > potentially blocking and clouds the example, thanks for catching that. > Conceivably though, it may be possible to use some other console output > that is non-blocking if Call_Police really does need to log something to > a console. Also, Call_Police does not necessarily need to involve a > task. For example, it may simply raise a signal on some hardware device > that calls 911, or turns on a siren, or flashing lights or whatever. This would mean that the hardware device encapsulated that task (e.g. HDD controller). I don't think this could be considered a realistic scenario. Hardware I/O on most platforms is too slow to be performed from a protected action. If you have an OS, it is 10-100 times slower, at least. Doing this within a protected action is not a good idea. One can imagine protected action as a being performed by a task with highest real-time priority. Without OS, considering low-level I/O, like DAQ boards, DMA access etc, the performance penalty might be even higher. > Timing_Events should handle a reasonable number of events in the system. > If your application has millions of these firing all over the place, > then scalability could become an issue, and perhaps for such a system, > some alternate design would be more appropriate. No, because these events need to be handled by somewhere. Million events handled by one task? That is the monitor task taking the shortest delay from a queue of. Million tasks will not work anyway. Speaking generally, IMO, the design should be driven by the worker tasks rather than by events, because the system load is inflicted by the workers, not by event propagation. An event implemented by protected actions are in effect synchronous or else you have some task that reads out some queue of events. There is no way to work around this. Either you process the event right at the spot it was triggered (=you don't have events at all), or else you postpone event handling to another task later. The bottom line, events need tasks or else do not exist... >> ----------- >> Timing_Events does not have any advantages over delay or asynchronous >> transfer of control. I guess it was provided for some low-level stuff like >> interrupts from hardware timers. However there was already a support for >> interrupts mapped into protected operations, so it really puzzles me why >> Timing_Events were added. > > I see timing events as being potentially useful reusable concurrency > component. > If you ever need something that looks like timing_events, then hopefully > it will save you from having to write your own. It may have utility in > some areas such as discrete event simulation, for example, if you need > something to coordinate multiple tasks and ensure that signalling events > occur and run to completion before before signaling subsequent events. This is IMO a different case, e.g. pulse events. Yes I have an implementation of pulse events. But I don't see why pulse events cannot be signaled from a scheduler task. The event source is unrelated to the way an event is handled. Basically Timing_Events saves you exactly one "scheduler" task, keeping in mind that the implementation of could deploy some hidden task (thread) anyway. It does not save you the worker task(s). -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de |