Yesterday I decided to look into adding std::future
support to ChaiScript. To be fair future is the return value of several other higher level threading constructs, so we don’t want just “std::future
,” we want enough support to make it usable.
ChaiScript works very well with functions and function objects, so ideally we want something like:
var f = run_in_a_thread(someFunction);
// do something
f.get(); // access the result value of someFunction, which was run in a separate thread
The C++ std function that fits the bill is std::async
. It takes a Function object and returns an std::future<ReturnType>
instantiation.
For our uses, we’re going to force the async to always run in a thread, just so we have predictability. To make this easier to implement, we’ll use a lambda to do the actual async call. Unfortunately, we do have to help ChaiScript determine the signature of the lambda, so that muddies up the syntax a little:
chai.add(fun<std::future<Boxed_Value> (const std::function<Boxed_Value> &)>(
[](const std::function<Boxed_Value> &t_bv) {
return std::async(std::launch::async, t_func);
}
), "async");
That takes care of async
but still doesn’t give us any support for actually accessing the value of the std::future
.
chai.add(fun(&std::future<Boxed_Value>::get), "get");
Done. Now our example becomes:
def someFunction() {
// do something
}
var f = async(someFunction); // Yes! ChaiScript *can* automatically convert someFunction into an std::function<> object
// do something
f.get(); // access the result value of someFunction, which was run in a separate thread
Just like magic, someFunction
is now running in a separate thread. Well, not 100% magic. If you’re going to have multiple writers on shared data you still need to provide the same protections for your data that you would have to in C++ directly. And, just like any other ChaiScript code - if it’s highly performance critical code - write a high level function in C++ and expose it to ChaiScript. Then you can use ChaiScript’s future
support to call the C++ function.
The complete implementation and examples can be seen on github. The complete implementation includes more in depth support for std::future
and some tests, but still fits in 50 lines of code.