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-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,6009c73a58f787a0 X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2002-01-13 08:29:21 PST Path: archiver1.google.com!news1.google.com!newsfeed.stanford.edu!news.tele.dk!small.news.tele.dk!130.133.1.3!fu-berlin.de!uni-berlin.de!ppp-2-240.cvx1.telinco.NET!not-for-mail From: "Nick Roberts" Newsgroups: comp.lang.ada Subject: Re: How to avoid unreferenced objects (mutexes etc) Date: Sun, 13 Jan 2002 16:12:17 -0000 Message-ID: References: NNTP-Posting-Host: ppp-2-240.cvx1.telinco.net (212.1.137.240) X-Trace: fu-berlin.de 1010938794 30164172 212.1.137.240 (16 [25716]) X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 5.50.4133.2400 X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4133.2400 Xref: archiver1.google.com comp.lang.ada:18863 Date: 2002-01-13T16:12:17+00:00 List-Id: wrote in message news:msb08.31576$%d4.3960804474@newssvr14.news.prodigy.com... > > and generally desirable to remove blocking calls from > > critical sections wherever possible. > Sometimes the "critical section" quite reasonably could last a > long time - when it's doing an IO operation using an IO channel, > for instance. That can be long, lots of other things can legitimately > run, but there better not be anyone else trying to use that same IO > channel at the same time. Claw.Sockets.Read, for instance, uses > this idiom, and a Read could block a particular socket for quite a while. Yes, but this isn't really a point at issue, is it? The situation you describe is a classic example of (the need for) the use of a buffer (is the terminology 'concurrent queue' these days?) to smooth out the timing differences between producer and consumer. If the target is a multi-processor machine, it can be particularly important (from the point of view of efficiency) that a task is used to do the buffering. > >address the problem of an exception leaving the resource in question in an > >unstable state. Nor does it do anything to mitigate the effects of > >accidentally omitting (or wrongly positioning) one of the seize or release > >calls. > The original question was about: > > Temp : Lock (Mutex_of_a_resource'Access); > >begin > > ... -- Safe access to the resource > >end; -- Mutex is released even if an exception propagates > and clearly there is no danger of omitting or wrongly positioning > anything, Absolutely true. My mistake. > or of problems with an exception. But there *is* a problem with exception handling: whilst the mutex will be released okay, the resource could be left in a bad state, and nothing (in Dmitry's example) is done to attempt to repair the damage. In fact, I note the possibility of building into the Finalize checks for the integrity of the resource's state (upon failure of which the resource could be reset). This technique certainly could mitigate the problems of leaving the resource in an unstable state, but it may be impractical or too inefficient. It could also be obfuscatory, in placing the clean-up code away from the code it cleans up. The advantage of having the clean-up code at the site of each (call to a) critical section (as per my examples) is that the clean-up code can then be specific to the code which causes the damage, and this is likely to be the more intelligible arrangement too. > In fact > > Temp : Lock (Mutex_of_a_resource'Access); > Something : Positive := Some_Value; > > would even be safe if Some_Value was negative, > ... > Once Initialize(Temp) has been called a matching Finalize(Temp) call is > guaranteed. Correct (apart from the possibility of the resource being left in a bad state, as just mentioned). > which is not a case a > local (after the "begin") exception handler would catch. Correct, but irrelevant. In my first example (with explicit seize and release), an exception propagated during elaboration of the relevant declarative region (where Lock is) would prevent the mutex ever being seized. In my second example (with the protected object holding the resource state), an exception propagated during elaboration of the declarative region of the protected procedure Do_Something_Critical would be propagated out of the procedure before it could possibly start altering the state of the resource (and the protected object is internally unlocked when the exception is propagated out). In my third example (with the task type), a call on the entry Do_Something_Critical does not cause the elaboration of a declarative region (but if it did, it too would be placed outside the actual critical code). Thus, these are all three perfectly safe from something going wrong during the elaboration of declarations. > > > The technique shown using a Limited_Controlled type to > > > automatically seize and release the semaphore is a standard Ada95 idiom. > And a good idiom, IMHO. I continue to disagree, for the reasons I have stated. I recognise that there will sometimes be occasions when the lower-level approach cannot be avoided (as with other situations where there is a choice between higher and lower levels of solution), but I hold that such occasions will be rare. (I also recognise that my O is rarely H ;-) -- Best wishes, Nick Roberts