Re: CheckAbort inside MathLink functions?
- To: mathgroup at smc.vnet.net
- Subject: [mg118141] Re: CheckAbort inside MathLink functions?
- From: "Alexey Popkov" <lehin.p at gmail.com>
- Date: Thu, 14 Apr 2011 04:48:59 -0400 (EDT)
- References: <000501cbf98b$537aacb0$bc0a440a@lehin> <201104131837.p3DIbT6e026930@wolfram.com>
Todd, Thank you for the responce. But I have two problems with your solution. The first one is that ReturnPacket[$Aborted] could not be distinguished from the same packet returned as the result of internal abort inside the code in the slave kernel: LinkWrite[link, Unevaluated[Abort[]]] This problem remains when using EvaluatePacket and EnterExpressionPacket. I wish to treat user-generated aborts in a different way than those generated by a program currently evaluating in the slave kernel. Is there a way to distinguish them? And another problem is with LinkWrite. There is a case when your solution does not work. It happens when a user press Alt+"." at the time of evaluating of LinkWrite: In[13]:= list=RandomReal[{0,1},1000001]; CheckAbort[AbortProtect[link=LinkLaunch[First[$CommandLine]<>" -mathlink"];LinkRead[link];With[{list=list},LinkWrite[link,Unevaluated[list.list]]];If[(result=LinkRead[link])===ReturnPacket[$Aborted],Abort[],Print[result]]],Print["!!"]] LinkClose[link] During evaluation of In[13]:= LinkObject::linkw: Unable to write data to closed link LinkObject[MathKernel -mathlink,12,8]. During evaluation of In[13]:= LinkObject::linkd: Unable to communicate with closed link LinkObject[MathKernel -mathlink,12,8]. During evaluation of In[13]:= $Failed During evaluation of In[13]:= LinkObject::linkn: Argument LinkObject[MathKernel -mathlink,12,8] in LinkClose[LinkObject[MathKernel -mathlink,12,8]] has an invalid LinkObject number; the link may be closed. >> Out[15]= LinkClose[LinkObject[MathKernel -mathlink,12,8]] The above Messages appear sometimes when I press Alt+"." after evaluating this code. It seems that LinkWrite closes the 'link' when Alt+"." was pressed during its evaluation. As the result, a couple of error messages appear. How to handle such situations correctly? Alexey ----- Original Message ----- From: "Todd Gayley" <tgayley at wolfram.com> To: "Alexey Popkov" <lehin.p at gmail.com>; "comp.soft-sys.math.mathematica" <mathgroup at smc.vnet.net> Sent: Wednesday, April 13, 2011 11:37 PM Subject: [mg118141] Re: CheckAbort inside MathLink functions? > 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 > >