Blocking calls in a Node.js Addon - c++

I'm developing a Node.js application that incorporates a Windows DLL. The DLL manages scientific equipment, for context.
My interface from Node to the DLL is going well, however the DLL has some non-deterministic calls that depend on the network topology and RF signals in the room. These calls can take anywhere from 10 seconds to 10 minutes.
I'd like to get these calls off Node's event loop, and even avoid AsyncWorkers. I'd like to put them in their own C++ threads. I'm worried that I don't know enough Node/V8 to approach the problem correctly, though I've attempted twice now.
Below is my attempt at spawning a thread to call a js callback, though I'm not sure if this is a good approach. I need the result of the call, and what I have so far is a 'daemon' in my node app that checks on a regular interval to retrieve results for completed tasks.
mTp in the snippet below is a threadpool implementation I've written. Runtask takes a C++ lambda as a parameter to be pushed onto my worker thread queue. mThreadStatus is a map from my thread 'handle', which is a string, to thread_status_t enum. mThreadResults is another map from the thread handle to a v8::Value that gets returned by the callback.
void
MyObj::SpawnThread(functionInput info) {
MyObj* obj = ObjectWrap::Unwrap<MyObj>(info.Holder());
obj->mTp.RunTask([&]() {
v8::Isolate::CreateParams cp;
v8::Isolate* tpIsolate = v8::Isolate::New(cp);
v8::Locker locker(tpIsolate);
v8::Isolate::Scope isolateScope(tpIsolate);
Nan::HandleScope scope;
auto global = obj->mContext.Get(tpIsolate)->Global();
auto handle = std::string(*v8::String::Utf8Value(info[0]->ToString()));
{
std::unique_lock<std::shared_mutex> lock(obj->mThreadStatusMutex);
obj->mThreadStatus[handle] = thread_status_t::running;
}
v8::Handle<v8::Function> f = v8::Handle<v8::Function>::Cast(info[1]);
v8::TryCatch trycatch(tpIsolate);
v8::Handle<v8::Value> result = f->Call(global, 0, nullptr);
if (result.IsEmpty()) {
v8::Local<v8::Value> exception = trycatch.Exception();
std::unique_lock<std::shared_mutex> lock(obj->mThreadStatusMutex);
obj->mThreadStatus[handle] = thread_status_t::error;
return;
}
{
std::unique_lock<std::shared_mutex> resultLock(obj->mThreadResultsMutex);
obj->mThreadResults[handle] = result;
}
std::unique_lock<std::shared_mutex> lock(obj->mThreadStatusMutex);
obj->mThreadStatus[handle] = completed;
tpIsolate->Dispose();
});
I'm envisioning my js looking like this to spawn a thread:
var ctx = this
this.myObj.spawnThread('startMeasurements', () => {
return ctx.myObj.startMeasurements()
})
And like this to get the result, in my 'daemon':
var status = this.myObj.getThreadStatus('startMeasurements')
if ( status === 'complete') {
// Publish returned information to front-end
}
else if (status === 'error') {
// Handle error
}
Has anyone solved this problem before? Does this look like a decent approach? Help with v8 is greatly appreciated. Thank you!

I have not solved a similar problem before, but the general way I would go about it is:
let the JavaScript code be oblivious of the threading
expose a function getMeasurements(callback) to JavaScript, implemented in C++
when the function is called, it gets itself a thread (either newly created, or from the pool) and instructs it to do the blocking external call; when that call is completed the thread signals its result to the main thread, which invokes the callback with it.
that way all communication with JavaScript code (i.e. all interaction with V8) happens on the main thread, and you only use background threads for the blocking calls.
I hope this helps!

Related

How to integrate Cap'n'Proto threads with non Cap'n'Proto threads?

How do I properly integrate Cap'n'Proto client usage with surrounding multi-threaded code? The Cap'n'Proto docs say that each Cap'n'Proto interface is single-threaded with a dedicated event loop. Additionally they recommend using Cap'n'Proto to communicate between threads. However, the docs don't seem to describe how non-Cap'n'Proto threads (e.g. the UI loop) could integrate with that. Even if could integrate Cap'n'Proto event loops with the UI loop in some places, other models like thread pools (Android Binder, global libdispatch queues) seem more challenging.
I think the solution is to cache the thread executor for the client thread in a synchronized place that the non-capnp thread will access it.
I believe though that the calling thread always needs to be on its own event loop as well to marry them but I just want to make sure that's actually the case. My initial attempt to do that in a simple unit test is failing. I created a KjLooperEventPort class (following the structure for the node libuv adapter) to marry KJ & ALooper on Android.
Then my test code is:
TEST(KjLooper, CrossThreadPromise) {
std::thread::id kjThreadId;
ConditionVariable<const kj::Executor*> executorCv{nullptr};
ConditionVariable<std::pair<bool, kj::Promise<void>>> looperThreadFinished{false, nullptr};
std::thread looperThread([&] {
auto looper = android::newLooper();
android::KjLooperEventPort kjEventPort{looper};
kj::WaitScope waitScope(kjEventPort.getKjLoop());
auto finished = kj::newPromiseAndFulfiller<void>();
looperThreadFinished.constructValueAndNotifyAll(true, kj::mv(finished.promise));
executorCv.waitNotValue(nullptr);
auto executor = executorCv.readCopy();
kj::Promise<void> asyncPromise = executor->executeAsync([&] {
ASSERT_EQ(std::this_thread::get_id(), kjThreadId);
});
asyncPromise = asyncPromise.then([tid = std::this_thread::get_id(), kjThreadId, &finished] {
std::cerr << "Running promise completion on original thread\n";
ASSERT_NE(tid, kjThreadId);
ASSERT_EQ(std::this_thread::get_id(), tid);
std::cerr << "Fulfilling\n";
finished.fulfiller->fulfill();
std::cerr << "Fulfilled\n";
});
asyncPromise.wait(waitScope);
});
std::thread kjThread([&] {
kj::Promise<void> finished = kj::NEVER_DONE;
looperThreadFinished.wait([&](auto& promise) {
finished = kj::mv(promise.second);
return promise.first;
});
auto ioContext = kj::setupAsyncIo();
kjThreadId = std::this_thread::get_id();
executorCv.setValueAndNotifyAll(&kj::getCurrentThreadExecutor());
finished.wait(ioContext.waitScope);
});
looperThread.join();
kjThread.join();
}
This crashes fulfilling the promise back to the kj thread.
terminating with uncaught exception of type kj::ExceptionImpl: kj/async.c++:1269: failed: expected threadLocalEventLoop == &loop || threadLocalEventLoop == nullptr; Event armed from different thread than it was created in. You must use
Executor to queue events cross-thread.
Most Cap'n Proto RPC and KJ Promise-related objects can only be accessed in the thread that created them. Resolving a promise cross-thread, for example, will fail, as you saw.
Some ways you could solve this include:
You can use kj::Executor to schedule code to run on a different thread's event loop. The calling thread does NOT need to be a KJ event loop thread if you use executeSync() -- however, this function blocks until the other thread has had a chance to wake up and execute the function. I'm not sure how well this will perform in practice; if it's a problem, there is probably room to extend the Executor interface to handle this use case more efficiently.
You can communicate between threads by passing messages over pipes or socketpairs (but sending big messages this way would involve a lot of unnecessary copying to/from the socket buffer).
You could signal another thread's event loop to wake up using a pipe, signal, or (on Linux) eventfd, then have it look for messages in a mutex-protected queue. (But kj::Executor mostly obsoletes this technique.)
It's possible, though not easy, to adapt KJ's event loop to run on top of other event loops, so that both can run in the same thread. For example, node-capnp adapts KJ to run on top of libuv.

Implementing a custom async task type and await

I am developing a C++ app in which i need to receive messages from an MQ and then parsing them according to their type and for a particular reason I want to make this process (receiving a single message followed by processing it) asynchronous. Since, I want to keep things as simple as possible in a way that the next developer would have no problem continuing the code, I have written a very small class to implement Asynchrony.
I first raise a new thread and pass a function to the thread:
task = new thread([&] {
result = fn();
isCompleted = true;
});
task->detach();
and in order to await the task I do the following:
while (!isCompleted && !(*cancelationToken))
{
Sleep(5);
}
state = 1; // marking the task as completed
So far there is no problem and I have not faced any bug or error but I am not sure if this is "a good way to do this" and my question is focused on determining this.
Read about std::future and std::async.
If your task runs in another core or processor, the variable isCompleted may become un-synchronized having two copies in core cache. So you may be waiting more than needed.
If you have to wait for something it is better to use a semaphore.
As said in comments, using standard methods is better anyway.

Reading all available messages from mpsc UnboundedReceiver without blocking unnecessarily

I have an futures::sync::mpsc::unbounded channel. I can send messages to the UnboundedSender<T> but have problems receiving them from the UnboundedReciever<T>.
I use the channel to send messages to the UI thread, and I have a function that gets called every frame, and I'd like to read all the available messages from the channel on each frame, without blocking the thread when there are no available messages.
From what I've read the Future::poll method is kind of what I need, I just poll, and if I get Async::Ready, I do something with the message, and if not, I just return from the function.
The problem is the poll panics when there is no task context (I'm not sure what that means or what to do about it).
What I tried:
let (sender, receiver) = unbounded(); // somewhere in the code, doesn't matter
// ...
let fut = match receiver.by_ref().collect().poll() {
Async::Ready(items_vec) => // do something on UI with items,
_ => return None
}
this panics because I don't have a task context.
Also tried:
let (sender, receiver) = unbounded(); // somewhere in the code, doesn't matter
// ...
let fut = receiver.by_ref().collect(); // how do I run the future?
tokio::runtime::current_thread::Runtime::new().unwrap().block_on(fut); // this blocks the thread when there are no items in the receiver
I would like help with reading the UnboundedReceiver<T> without blocking the thread when there are no items in the stream (just do nothing then).
Thanks!
You are using futures incorrectly -- you need a Runtime and a bit more boilerplate to get this to work:
extern crate tokio;
extern crate futures;
use tokio::prelude::*;
use futures::future::{lazy, ok};
use futures::sync::mpsc::unbounded;
use tokio::runtime::Runtime;
fn main() {
let (sender, receiver) = unbounded::<i64>();
let receiver = receiver.for_each(|result| {
println!("Got: {}", result);
Ok(())
});
let rt = Runtime::new().unwrap();
rt.executor().spawn(receiver);
let lazy_future = lazy(move || {
sender.unbounded_send(1).unwrap();
sender.unbounded_send(2).unwrap();
sender.unbounded_send(3).unwrap();
ok::<(), ()>(())
});
rt.block_on_all(lazy_future).unwrap();
}
Further reading, from Tokio's runtime model:
[...]in order to use Tokio and successfully execute tasks, an application must start an executor and the necessary drivers for the resources that the application’s tasks depend on. This requires significant boilerplate. To manage the boilerplate, Tokio offers a couple of runtime options. A runtime is an executor bundled with all necessary drivers to power Tokio’s resources. Instead of managing all the various Tokio components individually, a runtime is created and started in a single call.
Tokio offers a concurrent runtime and a single-threaded runtime. The concurrent runtime is backed by a multi-threaded, work-stealing executor. The single-threaded runtime executes all tasks and drivers on thee current thread. The user may pick the runtime with characteristics best suited for the application.

Using Callback function in Cassandra

I wanted to get suggestions regarding the proper way of implementing callback functions in Cassandra.
I had made some APIs using Cassandra's C++ driver. Given below is how I'd used the callback function to execute my query(l_stmt is the prepared statement and rtInsertCallback is the callback function):
CassFuture * l_query_future = cass_session_execute(RtConnectionObj::ms_session, l_stmt);
CassError l_returnCode = cass_future_set_callback(l_query_future,rtInsertCallback,NULL);
if(l_returnCode != CASS_OK)
{
printf("\n [ %s::%d ] Error \n",__FILE__,__LINE__);
}
cass_future_free(l_query_future);
Assuming, the above code is executed in Thread 1, as per my current understanding, the callback function will be executed when the future is set and that too in a separate thread(Thread 2). The callback function is like this:
void rtInsertCallback(CassFuture* l_csp_future, void *data)
{
CassError l_returnCode = cass_future_error_code(l_csp_future);
if (l_returnCode != CASS_OK)
{
printf("\n[%s::%d] %s ",__FILE__,__LINE__,cass_error_desc(l_returnCode));
}
else
{
printf("\n [%s::%d] Data Inserted successfully ...",__FILE__,__LINE__);
}
}
I want to know, is it possible that, before the future is set or before the CassError l_returnCode = cass_future_error_code(l_csp_future); statement gets executed in Thread 2, the future gets freed by Thread 1 due to which the above statement in thread 2 will be operating on a freed future? If yes, then what should be the proper way of handling such scenario? If this question does not make any sense(due to my misunderstanding of any concept), please explain. Thanks!
You are free to release the future in "Thread 1" after the callback statement. Callback will have its own copy of the future to work upon.
The Cassandra callback function will also take care of resource cleanup after it gets processed. So we don't have to explicitly free the future.
Code Sample can be found here
https://github.com/datastax/cpp-driver/blob/master/examples/callbacks/callbacks.c

Synchronous and ASynchronous APIs

I am developing a library, which provides some time consuming services. I need to have two versions of each API, one for synchronous function call and the other for asynchronous.
Library user should decide which version to use, a service result might be crucial for continue of system operation (synch call). The same operation might be needed to be done in different worker thread as it result is not needed to continue (asynch call).
What are the problems of this approach?
Is there any better way?
Are there popular libraries which provides both sync/async for the same API (Without using external events or threads) ?
Here is an example of what I am going to provide:
enum StuffStatus
{
SUCCEED,
FAILED,
STILL_RUNNING
};
class IServiceCallback
{
public:
void lengthyStuffCallback(StuffStatus status);
};
class MyServiceClass
{
public:
StuffStatus doSomeLengthStuff(IServiceCallback* callback)
{
if( callback == NULL ) // user wants sync. call
{
// do all operations in caller context
return SUCCEED;
}else{
// save the callback, queue the request in a separate worker thread.
// and after the worker thread finishes the job it calls callback->lengthyStuffCallback(SUCCEED) from its context.
return STILL_RUNNING;
}
}
};
EDIT:
As ' Matthieu M.' mentioned, In my service I need asynchronous with Continuation Passing Style (callback after API finish).
You might want to consider to provide only the synchronous operation and advise users to use std::future<...> (or a similar facility if you can't use C++ 2011) if they want an asynchronous version of the call!
std::future<StuffStatus> async(std::async(&MyServiceClass::doSomeLengthyStuff,
&service));
// do other stuff
StuffStatus status = async.get(); // get the result, possibly using a blocking wait