MathGroup Archive 2011

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: CheckAbort inside MathLink functions?

  • To: mathgroup at smc.vnet.net
  • Subject: [mg118138] Re: CheckAbort inside MathLink functions?
  • From: Todd Gayley <tgayley at wolfram.com>
  • Date: Thu, 14 Apr 2011 04:48:26 -0400 (EDT)
  • References: <000501cbf98b$537aacb0$bc0a440a@lehin>

At 10:31 PM 4/12/2011, Alexey Popkov wrote:
>Hello,
>
>It seems that that such MathLink functions as LinkWrite and LinkRead have
>something like its own internal CheckAbort that absorbs user-generated
>aborts, and does not propagate them further.
>
>This can be easily shown with LinkRead:
>
>link = LinkLaunch[First[$CommandLine] <> " -mathlink"];
>LinkRead[link];
>LinkWrite[link, Unevaluated[Pause[100]]];
>CheckAbort[AbortProtect[Print[LinkRead[link]]], Print["!!"]]
>
>If we press Alt+. after evaluating the above code we get only the following
>output:
>
>During evaluation of In[6]:= ReturnPacket[$Aborted]
>
>But Print["!!"] is not evaluated although we have generated Abort[] exactly
>inside CheckAbort.
>
>One can see that the abort we made by pressing Alt+. was absorbed by
>LinkRead.
>
>My problem is that it breaks my own flow control of evaluation based on
>CheckAbort.
>
>Is there a way to intercept aborts absorbed by such functions as LinkRead
>and LinkWrite for having ability to catch user-generated aborts?


Alexey,

The behavior you describe is a feature, and writing correct 
Mathematica programs that call external programs via MathLink would 
be difficult without it. The behavior you have discovered is this: If 
a user abort is detected while the kernel is blocking in a LinkRead 
call, the abort is not handled like a normal abort request, but 
instead it is propagated to the external program (specifically, a 
MathLink MLAbortMessage is sent over the link that the kernel is reading from).

To see why this is useful, consider the following pseudocode user 
program that calls an external program via MathLink:

     LinkWrite[link, something];
     While[haventReceivedFinalPacket,
         LinkRead[link]
     ]

Consider what happens if a user of this program hits Alt-. to trigger 
an abort while it is running, say between calls to LinkRead. The 
kernel will exit from the While loop, leaving unread packets on the 
link. The external program is now effectively broken, because future 
attempts to use it will end up reading packets left over from the 
previous call.

The correct way to fix this is to wrap the entire operation in 
AbortProtect, making it atomic. Once you start an transaction with 
the external program, there is no way the user can inadvertently 
prevent it from finishing by requesting an abort at an inopportune time.

     AbortProtect[
         LinkWrite[link, something];
             While[haventReceivedFinalPacket,
             LinkRead[link]
         ]
     ]

We have now fixed a bug in our program by making sure it won't break 
horribly if a user tries to abort it. But what we really want is to 
honor the user's request for an abort. As we've just discussed, we 
cannot do this by simply backing out of a LinkRead. The sensible 
thing is for LinkRead to forward the abort request to the external 
program in the hopes that the external program will pay attention to 
it. After all, the external program "owns" the computation at this 
point. MathLink programs have a means of detecting abort messages 
arriving over the link, and can clean up and return an appropriate result.

For all this to work properly, AbortProtect must not prevent LinkRead 
from forwarding the abort, and it does in fact behave this way.

In the case of your program, Alexey, this behavior is not "breaking 
your flow control", it is absolutely required to avoid problems. When 
you execute the program you showed, and hit Alt-. and get back 
ReturnPacket[$Aborted], you are seeing the behavior I described 
above. The abort is forwarded to the slave kernel, which aborts its 
evaluation of Pause[100] and returns $Aborted. If you want to have 
the Alt-. propagate all the way back up to abort the entire top-level 
program that was executing, which is typically the right behavior, 
what you need to do is look for $Aborted returning from the slave 
kernel and then call Abort[] yourself:

     AbortProtect[
         LinkWrite[link, Unevaluated[Pause[100]]];
         result = LinkRead[link];
         If[result === ReturnPacket[$Aborted],
             (* Re-fire the Abort, which will trigger as soon as the 
AbortProtect block ends. *)
             Abort[]
         ]
     ]

If you want to use CheckAbort to catch the re-fired Abort, that will work fine.


--Todd



  • Prev by Date: FindFit[] Blues
  • Next by Date: Re: CheckAbort inside MathLink functions?
  • Previous by thread: CheckAbort inside MathLink functions?
  • Next by thread: Re: CheckAbort inside MathLink functions?