简体   繁体   中英

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

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 (ie, 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).

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, eg 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++.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM