From simon.urbanek at r-project.org  Tue Apr 26 15:21:32 2011
From: simon.urbanek at r-project.org (Simon Urbanek)
Date: Tue, 26 Apr 2011 09:21:32 -0400
Subject: [Rd] Interrupting C++ code execution
In-Reply-To: <4DB6ACCB.8050606@arcor.de>
References: <4DB53D47.7060903@arcor.de>
	<85607CA7-D76F-4210-9C6E-F3E9F26F7D0E@r-project.org>
	<F1EAEEC8-7828-403F-BF2D-10A4F925B4E6@r-project.org>
	<201104252018.01541.thomas.friedrichsmeier@ruhr-uni-bochum.de>
	<4DB6ACCB.8050606@arcor.de>
Message-ID: <EE5FF473-368C-4EEE-893A-33783D462AC5@r-project.org>


On Apr 26, 2011, at 7:30 AM, schattenpflanze at arcor.de wrote:

> I have tested the solutions suggested by Simon and Thomas on a Linux machine. These are my findings:
> 
>> On Windows you can look at the variable "UserBreak", available from
>> Rembedded.h. Outside of Windows, you can look at R_interrupts_pending,
>> available from R_ext/GraphicsDevice.h. R_ext/GraphicsDevice.h also has
>> R_interrupts_suspended, which you may or may not want to take into account,
>> depending on your use-case.
> I did not manage to get this to work. Neither R_interrupts_pending nor R_interrupts_suspended seem to change when I press ctrl+c. Perhaps this is due to the fact that I run R in a terminal without any graphical interface?
> 

Thomas' suggestion was not aimed at your problem - it was sort of the inverse (more at your Qt question). If you want to interrupt R you can mess with those flags and them let R run the event loop. It doesn't work in your (original) case.


>> static void chkIntFn(void *dummy) {
>>  R_CheckUserInterrupt();
>> }
>> // this will call the above in a top-level context so it won't longjmp-out of your context
>> bool checkInterrupt() {
>>  return (R_ToplevelExec(chkIntFn, NULL) == FALSE);
>> }
>> // your code somewhere ...
>> if (checkInterrupt()) { // user interrupted ... }
> This solution works perfectly! It takes slightly longer to call this function than the plan R_CheckUserInterrupt() call, but in any reasonable scenario, the additional time is absolutely insignificant.
> 
> Inside OpenMP parallel for constructs, one has to make sure that only the thread satisfying omp_get_thread_num()==0 makes the call (the 'master' construct cannot be nested inside a loop). I can then set a flag, which is queried by every thread in every loop cycle, causing fast termination of the parallel loop. After the loop, I throw an exception. Thus, my code is terminated gracefully with minimal effort. I can do additional cleanup operations (which usually is not necessary, since I use smart pointers), and report details on the interrupt to the user.
> 
> With my limited testing, so far I have not noticed any downsides. Of course, there is the obvious drawback of not being supported officially (and thus maybe being subject to change),

Actually, it is in the official API (Rinternals.h) so I don't think that is the issue.


> the question of portability, and the question of interoperability with other errors.
> 

It is portable as well, so I'd say the main concern is what happens when events trigger something that is not related to you and you eat those errors. They will act as user-interrupt to you even if it's not what the user intended. One could argue that it's the lesser of the evils, because if you don't do anything R will just block so those events would have to wait until you're done anyway.


> Moreover, I have found an old thread discussing almost the same topic:
> http://tolstoy.newcastle.edu.au/R/e4/devel/08/05/1686.html .
> The thread was created in 2008, so the issue is not really a new one. The solution proposed there is actually the same as the one suggested by Simon, namely using R_ToplevelExec().
> 

Interesting - I'm glad Luke also suggested C-level onexit bac then - it is something I was thinking about before ..

Cheers,
Simon


> An officially supported, portable solution would of course be much appreciated!
> 
> 
> Best regards,
> Peter
> 
> 



[Rd] Interrupting C++ code execution
Simon Urbanek