The Napi::ThreadSafeFunction type provides APIs for threads to communicate
with the addon's main thread to invoke JavaScript functions on their behalf.
Documentation can be found for an overview of the API, as well
as differences between the two thread-safe function
APIs.
Creates a new empty instance of Napi::ThreadSafeFunction.
Napi::Function::ThreadSafeFunction();
Creates a new instance of the Napi::ThreadSafeFunction object.
Napi::ThreadSafeFunction::ThreadSafeFunction(napi_threadsafe_function tsfn);
tsfn: The napi_threadsafe_function which is a handle for an existingReturns a non-empty Napi::ThreadSafeFunction instance. When using this
constructor, only use the Blocking(void*) / NonBlocking(void*) overloads;
the Callback and templated data* overloads should not be used. See below
for additional details.
Creates a new instance of the Napi::ThreadSafeFunction object. The New
function has several overloads for the various optional parameters: skip the
optional parameter for that specific overload.
New(napi_env env,
const Function& callback,
const Object& resource,
ResourceString resourceName,
size_t maxQueueSize,
size_t initialThreadCount,
ContextType* context,
Finalizer finalizeCallback,
FinalizerDataType* data);
env: The napi_env environment in which to construct theNapi::ThreadSafeFunction object.callback: The Function to call from another thread.[optional] resource: An object associated with the async work that will beresourceName: A JavaScript string to provide an identifier for the kind ofmaxQueueSize: Maximum size of the queue. 0 for no limit.initialThreadCount: The initial number of threads, including the main[optional] context: Data to attach to the resulting ThreadSafeFunction. ItGetContext().[optional] finalizeCallback: Function to call when the ThreadSafeFunctionuv_thread_join(). It is important that, aside from the main loop thread,void operator()(Env env, DataType* data, ContextType* hint), skipping data or hint if they are not provided. CanGetContext().[optional] data: Data to be passed to finalizeCallback.Returns a non-empty Napi::ThreadSafeFunction instance.
Add a thread to this thread-safe function object, indicating that a new thread
will start making use of the thread-safe function.
napi_status Napi::ThreadSafeFunction::Acquire()
Returns one of:
- napi_ok: The thread has successfully acquired the thread-safe function
for its use.
- napi_closing: The thread-safe function has been marked as closing via a
previous call to Abort().
Indicate that an existing thread will stop making use of the thread-safe
function. A thread should call this API when it stops making use of this
thread-safe function. Using any thread-safe APIs after having called this API
has undefined results in the current thread, as it may have been destroyed.
napi_status Napi::ThreadSafeFunction::Release()
Returns one of:
- napi_ok: The thread-safe function has been successfully released.
- napi_invalid_arg: The thread-safe function's thread-count is zero.
- napi_generic_failure: A generic error occurred when attempting to release
the thread-safe function.
"Abort" the thread-safe function. This will cause all subsequent APIs associated
with the thread-safe function except Release() to return napi_closing even
before its reference count reaches zero. In particular, BlockingCall andNonBlockingCall() will return napi_closing, thus informing the threads that
it is no longer possible to make asynchronous calls to the thread-safe function.
This can be used as a criterion for terminating the thread. Upon receiving a
return value of napi_closing from a thread-safe function call a thread must
make no further use of the thread-safe function because it is no longer
guaranteed to be allocated.
napi_status Napi::ThreadSafeFunction::Abort()
Returns one of:
- napi_ok: The thread-safe function has been successfully aborted.
- napi_invalid_arg: The thread-safe function's thread-count is zero.
- napi_generic_failure: A generic error occurred when attempting to abort
the thread-safe function.
Calls the Javascript function in either a blocking or non-blocking fashion.
- BlockingCall(): the API blocks until space becomes available in the queue.
Will never block if the thread-safe function was created with a maximum queue
size of 0.
- NonBlockingCall(): will return napi_queue_full if the queue was full,
preventing data from being successfully added to the queue.
There are several overloaded implementations of BlockingCall() andNonBlockingCall() for use with optional parameters: skip the optional
parameter for that specific overload.
These specific function overloads should only be used on a ThreadSafeFunction
created via ThreadSafeFunction::New.
napi_status Napi::ThreadSafeFunction::BlockingCall(DataType* data, Callback callback) const
napi_status Napi::ThreadSafeFunction::NonBlockingCall(DataType* data, Callback callback) const
[optional] data: Data to pass to callback.[optional] callback: C++ function that is invoked on the main thread. TheThreadSafeFunction's JavaScript callback function toNapi::Function in its parameters and the DataType* data pointervoid operator()(Napi::Env env, Function jsCallback, DataType* data), skipping data if not provided. It is notMakeCallback() because N-API runscallback in a context appropriate for callbacks.These specific function overloads should only be used on a ThreadSafeFunction
created via ThreadSafeFunction(napi_threadsafe_function).
napi_status Napi::ThreadSafeFunction::BlockingCall(void* data) const
napi_status Napi::ThreadSafeFunction::NonBlockingCall(void* data) const
data: Data to pass to call_js_cb specified when creating the thread-safenapi_create_threadsafe_function.Returns one of:
- napi_ok: The call was successfully added to the queue.
- napi_queue_full: The queue was full when trying to call in a non-blocking
method.
- napi_closing: The thread-safe function is aborted and cannot accept more
calls.
- napi_invalid_arg: The thread-safe function is closed.
- napi_generic_failure: A generic error occurred when attempting to add to the
queue.
#include <chrono>
#include <thread>
#include <napi.h>
using namespace Napi;
std::thread nativeThread;
ThreadSafeFunction tsfn;
Value Start( const CallbackInfo& info )
{
Napi::Env env = info.Env();
if ( info.Length() < 2 )
{
throw TypeError::New( env, "Expected two arguments" );
}
else if ( !info[0].IsFunction() )
{
throw TypeError::New( env, "Expected first arg to be function" );
}
else if ( !info[1].IsNumber() )
{
throw TypeError::New( env, "Expected second arg to be number" );
}
int count = info[1].As<Number>().Int32Value();
// Create a ThreadSafeFunction
tsfn = ThreadSafeFunction::New(
env,
info[0].As<Function>(), // JavaScript function called asynchronously
"Resource Name", // Name
0, // Unlimited queue
1, // Only one thread will use this initially
[]( Napi::Env ) { // Finalizer used to clean threads up
nativeThread.join();
} );
// Create a native thread
nativeThread = std::thread( [count] {
auto callback = []( Napi::Env env, Function jsCallback, int* value ) {
// Transform native data into JS data, passing it to the provided
// `jsCallback` -- the TSFN's JavaScript function.
jsCallback.Call( {Number::New( env, *value )} );
// We're finished with the data.
delete value;
};
for ( int i = 0; i < count; i++ )
{
// Create new data
int* value = new int( clock() );
// Perform a blocking call
napi_status status = tsfn.BlockingCall( value, callback );
if ( status != napi_ok )
{
// Handle error
break;
}
std::this_thread::sleep_for( std::chrono::seconds( 1 ) );
}
// Release the thread-safe function
tsfn.Release();
} );
return Boolean::New(env, true);
}
Napi::Object Init( Napi::Env env, Object exports )
{
exports.Set( "start", Function::New( env, Start ) );
return exports;
}
NODE_API_MODULE( clock, Init )
The above code can be used from JavaScript as follows:
const { start } = require('bindings')('clock');
start(function () {
console.log("JavaScript callback called with arguments", Array.from(arguments));
}, 5);
When executed, the output will show the value of clock() five times at one
second intervals:
JavaScript callback called with arguments [ 84745 ]
JavaScript callback called with arguments [ 103211 ]
JavaScript callback called with arguments [ 104516 ]
JavaScript callback called with arguments [ 105104 ]
JavaScript callback called with arguments [ 105691 ]