Skip to content

Instantly share code, notes, and snippets.

@jcheng5
Last active July 10, 2017 22:19
Show Gist options
  • Save jcheng5/c2ec5c0b025162ab2eddb4d7d42339f1 to your computer and use it in GitHub Desktop.
Save jcheng5/c2ec5c0b025162ab2eddb4d7d42339f1 to your computer and use it in GitHub Desktop.

This snippet shows how you could use later to create an API that can be called on a background thread, to perform an arbitrary task on the main R thread, and return the result to the background thread. The background thread blocks until the result is returned from the main R thread.

#include <Rcpp.h>
#include <later_api.h>
#include <boost/function.hpp>
#include "tinythread.h"
// === Public API ===============================
template <class TOutput>
TOutput invoke(boost::function<TOutput ()> task);
// === Implementation ===========================
namespace {
template <class TOutput>
class Invoke {
public:
Invoke(boost::function<TOutput ()> task) : _task(task) {
}
TOutput operator ()() {
tthread::lock_guard<tthread::recursive_mutex> guard(_m);
later::later(mainThreadCallback, this, 0);
_cond.wait(_m);
return _result;
}
private:
// This method is run on the main thread; it does some threading
// boilerplate, and invokes the task.
void onMainThread() {
tthread::lock_guard<tthread::recursive_mutex> guard(_m);
this->_result = this->_task();
_cond.notify_all();
}
// This static method exists only because later::later needs a
// plain C function pointer, not a boost::function or anything
// fancy like that. Otherwise we'd pass the onMainThread() method
// directly to later::later, and get rid of this.
static void mainThreadCallback(void* data) {
Invoke<TOutput>* self = (Invoke<TOutput>*)data;
self->onMainThread();
}
boost::function<TOutput ()> _task;
TOutput _result;
tthread::recursive_mutex _m;
tthread::condition_variable _cond;
};
} // namespace
template <class TOutput>
TOutput invoke(boost::function<TOutput ()> task) {
return Invoke<TOutput>(task)();
}
// === Example ==================================
#include <boost/bind.hpp>
using namespace Rcpp;
// The operation to perform on the main thread. You would replace
// this with code that invokes R code.
double negate(double val) {
return -val;
}
// Code to execute on the background thread
void background_test(void*) {
tthread::this_thread::sleep_for(tthread::chrono::seconds(5));
// Invoke negate(10.0) from the R thread, and wait for the result
double result = invoke<double>(boost::bind(negate, 10.0));
printf("%lf", result);
}
// [[Rcpp::export]]
void rcpp_hello_world() {
tthread::thread t(background_test, NULL);
t.detach();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment