Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R: How to write interruptible C++ function, and recover partial results

Tags:

c++

r

We are writing an R package, the core of which is written in C++ and basically consists of one long-running loop:

void core_func(double* data)
{
    while (!done)
    {
        // update 'data'
    }
}

The call is made using R's .C mechanism:

ans <- .C("core_func", data = as.double(data))$data

We would like for the user to be able to interrupt the function, and to recover the partial results (i.e., contents of *data at point of interrupt).

Question: Is this in any way possible?

Our efforts to come up with a solution have so far produced this post, which - if interpreted correctly - gives an indication on how to cleanly exit from the loop.

void core_func(double* data)
{
    while (!done && !checkInterrupt())
    {
        // update 'data'
    }
}

What we haven't figured out, is how to pass the partial results back to the caller (aka. R user).

Solution: It seems the solution was right in front of us all this time. The approach proposed by Simon Urbanek in the abovementioned post (original post here) covers all the bases. Making use of the checkInterrupt() function, the C++ code can be designed to exit cleanly upon a user interrupt; and, most importantly, control is then handed back to the calling .C function in R, which can return the (partial) results in an orderly manner.

Thanks to @Jeroen for clearing things up (and for the hint about searching for code in METACRAN)!

Note concerning the Update in Jeroen's answer: We wish to keep the C++ code R-agnostic (precluding a dependency on Rcpp).

like image 701
Marc H. Avatar asked Nov 12 '16 13:11

Marc H.


Video Answer


1 Answers

Update: the easiest approach is to call C++ via Rcpp and check via Rcpp::checkUserInterrupt. This automatically raises an exception if a interrupt is pending. See section 2.4 of rcpp attributes.

Original answer: R allows for checking for SIGINT via the C API:

R_CheckUserInterrupt();

However this function will immediately jump back to the console if an interruption is pending which can leave your C/C++ code in an undefined state.

A trick suggested by Simon Urbanek is to use the following wrapper code:

/* Check for interrupt without long jumping */
void check_interrupt_fn(void *dummy) {
  R_CheckUserInterrupt();
}

int pending_interrupt() {
  return !(R_ToplevelExec(check_interrupt_fn, NULL));
}

You can now call pending_interrupt() to check if an interruption is pending and deal with it yourself, e.g. raise some special C++ exception or simply return intermediate results. Make sure you read Simon's comments in the post to understand the consequences of this approach.

I have personally only used this via C to interrupt downloads in the curl package. Perhaps you can search metacran for examples that use R_CheckUserInterrupt from C++.

like image 181
Jeroen Ooms Avatar answered Oct 16 '22 20:10

Jeroen Ooms