18c339a94Sopenharmony_ci# ThreadSafeFunction 28c339a94Sopenharmony_ci 38c339a94Sopenharmony_ciThe `Napi::ThreadSafeFunction` type provides APIs for threads to communicate 48c339a94Sopenharmony_ciwith the addon's main thread to invoke JavaScript functions on their behalf. 58c339a94Sopenharmony_ciDocumentation can be found for an [overview of the API](threadsafe.md), as well 68c339a94Sopenharmony_cias [differences between the two thread-safe function 78c339a94Sopenharmony_ciAPIs](threadsafe.md#implementation-differences). 88c339a94Sopenharmony_ci 98c339a94Sopenharmony_ci## Methods 108c339a94Sopenharmony_ci 118c339a94Sopenharmony_ci### Constructor 128c339a94Sopenharmony_ci 138c339a94Sopenharmony_ciCreates a new empty instance of `Napi::ThreadSafeFunction`. 148c339a94Sopenharmony_ci 158c339a94Sopenharmony_ci```cpp 168c339a94Sopenharmony_ciNapi::Function::ThreadSafeFunction(); 178c339a94Sopenharmony_ci``` 188c339a94Sopenharmony_ci 198c339a94Sopenharmony_ci### Constructor 208c339a94Sopenharmony_ci 218c339a94Sopenharmony_ciCreates a new instance of the `Napi::ThreadSafeFunction` object. 228c339a94Sopenharmony_ci 238c339a94Sopenharmony_ci```cpp 248c339a94Sopenharmony_ciNapi::ThreadSafeFunction::ThreadSafeFunction(napi_threadsafe_function tsfn); 258c339a94Sopenharmony_ci``` 268c339a94Sopenharmony_ci 278c339a94Sopenharmony_ci- `tsfn`: The `napi_threadsafe_function` which is a handle for an existing 288c339a94Sopenharmony_ci thread-safe function. 298c339a94Sopenharmony_ci 308c339a94Sopenharmony_ciReturns a non-empty `Napi::ThreadSafeFunction` instance. When using this 318c339a94Sopenharmony_ciconstructor, only use the `Blocking(void*)` / `NonBlocking(void*)` overloads; 328c339a94Sopenharmony_cithe `Callback` and templated `data*` overloads should _not_ be used. See below 338c339a94Sopenharmony_cifor additional details. 348c339a94Sopenharmony_ci 358c339a94Sopenharmony_ci### New 368c339a94Sopenharmony_ci 378c339a94Sopenharmony_ciCreates a new instance of the `Napi::ThreadSafeFunction` object. The `New` 388c339a94Sopenharmony_cifunction has several overloads for the various optional parameters: skip the 398c339a94Sopenharmony_cioptional parameter for that specific overload. 408c339a94Sopenharmony_ci 418c339a94Sopenharmony_ci```cpp 428c339a94Sopenharmony_ciNew(napi_env env, 438c339a94Sopenharmony_ci const Function& callback, 448c339a94Sopenharmony_ci const Object& resource, 458c339a94Sopenharmony_ci ResourceString resourceName, 468c339a94Sopenharmony_ci size_t maxQueueSize, 478c339a94Sopenharmony_ci size_t initialThreadCount, 488c339a94Sopenharmony_ci ContextType* context, 498c339a94Sopenharmony_ci Finalizer finalizeCallback, 508c339a94Sopenharmony_ci FinalizerDataType* data); 518c339a94Sopenharmony_ci``` 528c339a94Sopenharmony_ci 538c339a94Sopenharmony_ci- `env`: The `napi_env` environment in which to construct the 548c339a94Sopenharmony_ci `Napi::ThreadSafeFunction` object. 558c339a94Sopenharmony_ci- `callback`: The `Function` to call from another thread. 568c339a94Sopenharmony_ci- `[optional] resource`: An object associated with the async work that will be 578c339a94Sopenharmony_ci passed to possible async_hooks init hooks. 588c339a94Sopenharmony_ci- `resourceName`: A JavaScript string to provide an identifier for the kind of 598c339a94Sopenharmony_ci resource that is being provided for diagnostic information exposed by the 608c339a94Sopenharmony_ci async_hooks API. 618c339a94Sopenharmony_ci- `maxQueueSize`: Maximum size of the queue. `0` for no limit. 628c339a94Sopenharmony_ci- `initialThreadCount`: The initial number of threads, including the main 638c339a94Sopenharmony_ci thread, which will be making use of this function. 648c339a94Sopenharmony_ci- `[optional] context`: Data to attach to the resulting `ThreadSafeFunction`. It 658c339a94Sopenharmony_ci can be retreived by calling `GetContext()`. 668c339a94Sopenharmony_ci- `[optional] finalizeCallback`: Function to call when the `ThreadSafeFunction` 678c339a94Sopenharmony_ci is being destroyed. This callback will be invoked on the main thread when the 688c339a94Sopenharmony_ci thread-safe function is about to be destroyed. It receives the context and the 698c339a94Sopenharmony_ci finalize data given during construction (if given), and provides an 708c339a94Sopenharmony_ci opportunity for cleaning up after the threads e.g. by calling 718c339a94Sopenharmony_ci `uv_thread_join()`. It is important that, aside from the main loop thread, 728c339a94Sopenharmony_ci there be no threads left using the thread-safe function after the finalize 738c339a94Sopenharmony_ci callback completes. Must implement `void operator()(Env env, DataType* data, 748c339a94Sopenharmony_ci ContextType* hint)`, skipping `data` or `hint` if they are not provided. Can 758c339a94Sopenharmony_ci be retrieved via `GetContext()`. 768c339a94Sopenharmony_ci- `[optional] data`: Data to be passed to `finalizeCallback`. 778c339a94Sopenharmony_ci 788c339a94Sopenharmony_ciReturns a non-empty `Napi::ThreadSafeFunction` instance. 798c339a94Sopenharmony_ci 808c339a94Sopenharmony_ci### Acquire 818c339a94Sopenharmony_ci 828c339a94Sopenharmony_ciAdd a thread to this thread-safe function object, indicating that a new thread 838c339a94Sopenharmony_ciwill start making use of the thread-safe function. 848c339a94Sopenharmony_ci 858c339a94Sopenharmony_ci```cpp 868c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::Acquire() const 878c339a94Sopenharmony_ci``` 888c339a94Sopenharmony_ci 898c339a94Sopenharmony_ciReturns one of: 908c339a94Sopenharmony_ci- `napi_ok`: The thread has successfully acquired the thread-safe function 918c339a94Sopenharmony_cifor its use. 928c339a94Sopenharmony_ci- `napi_closing`: The thread-safe function has been marked as closing via a 938c339a94Sopenharmony_ciprevious call to `Abort()`. 948c339a94Sopenharmony_ci 958c339a94Sopenharmony_ci### Release 968c339a94Sopenharmony_ci 978c339a94Sopenharmony_ciIndicate that an existing thread will stop making use of the thread-safe 988c339a94Sopenharmony_cifunction. A thread should call this API when it stops making use of this 998c339a94Sopenharmony_cithread-safe function. Using any thread-safe APIs after having called this API 1008c339a94Sopenharmony_cihas undefined results in the current thread, as it may have been destroyed. 1018c339a94Sopenharmony_ci 1028c339a94Sopenharmony_ci```cpp 1038c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::Release() const 1048c339a94Sopenharmony_ci``` 1058c339a94Sopenharmony_ci 1068c339a94Sopenharmony_ciReturns one of: 1078c339a94Sopenharmony_ci- `napi_ok`: The thread-safe function has been successfully released. 1088c339a94Sopenharmony_ci- `napi_invalid_arg`: The thread-safe function's thread-count is zero. 1098c339a94Sopenharmony_ci- `napi_generic_failure`: A generic error occurred when attempting to release 1108c339a94Sopenharmony_cithe thread-safe function. 1118c339a94Sopenharmony_ci 1128c339a94Sopenharmony_ci### Abort 1138c339a94Sopenharmony_ci 1148c339a94Sopenharmony_ci"Abort" the thread-safe function. This will cause all subsequent APIs associated 1158c339a94Sopenharmony_ciwith the thread-safe function except `Release()` to return `napi_closing` even 1168c339a94Sopenharmony_cibefore its reference count reaches zero. In particular, `BlockingCall` and 1178c339a94Sopenharmony_ci`NonBlockingCall()` will return `napi_closing`, thus informing the threads that 1188c339a94Sopenharmony_ciit is no longer possible to make asynchronous calls to the thread-safe function. 1198c339a94Sopenharmony_ciThis can be used as a criterion for terminating the thread. Upon receiving a 1208c339a94Sopenharmony_cireturn value of `napi_closing` from a thread-safe function call a thread must 1218c339a94Sopenharmony_cimake no further use of the thread-safe function because it is no longer 1228c339a94Sopenharmony_ciguaranteed to be allocated. 1238c339a94Sopenharmony_ci 1248c339a94Sopenharmony_ci```cpp 1258c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::Abort() const 1268c339a94Sopenharmony_ci``` 1278c339a94Sopenharmony_ci 1288c339a94Sopenharmony_ciReturns one of: 1298c339a94Sopenharmony_ci- `napi_ok`: The thread-safe function has been successfully aborted. 1308c339a94Sopenharmony_ci- `napi_invalid_arg`: The thread-safe function's thread-count is zero. 1318c339a94Sopenharmony_ci- `napi_generic_failure`: A generic error occurred when attempting to abort 1328c339a94Sopenharmony_cithe thread-safe function. 1338c339a94Sopenharmony_ci 1348c339a94Sopenharmony_ci### BlockingCall / NonBlockingCall 1358c339a94Sopenharmony_ci 1368c339a94Sopenharmony_ciCalls the Javascript function in either a blocking or non-blocking fashion. 1378c339a94Sopenharmony_ci- `BlockingCall()`: the API blocks until space becomes available in the queue. 1388c339a94Sopenharmony_ci Will never block if the thread-safe function was created with a maximum queue 1398c339a94Sopenharmony_ci size of `0`. 1408c339a94Sopenharmony_ci- `NonBlockingCall()`: will return `napi_queue_full` if the queue was full, 1418c339a94Sopenharmony_ci preventing data from being successfully added to the queue. 1428c339a94Sopenharmony_ci 1438c339a94Sopenharmony_ciThere are several overloaded implementations of `BlockingCall()` and 1448c339a94Sopenharmony_ci`NonBlockingCall()` for use with optional parameters: skip the optional 1458c339a94Sopenharmony_ciparameter for that specific overload. 1468c339a94Sopenharmony_ci 1478c339a94Sopenharmony_ci**These specific function overloads should only be used on a `ThreadSafeFunction` 1488c339a94Sopenharmony_cicreated via `ThreadSafeFunction::New`.** 1498c339a94Sopenharmony_ci 1508c339a94Sopenharmony_ci```cpp 1518c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::BlockingCall(DataType* data, Callback callback) const 1528c339a94Sopenharmony_ci 1538c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::NonBlockingCall(DataType* data, Callback callback) const 1548c339a94Sopenharmony_ci``` 1558c339a94Sopenharmony_ci 1568c339a94Sopenharmony_ci- `[optional] data`: Data to pass to `callback`. 1578c339a94Sopenharmony_ci- `[optional] callback`: C++ function that is invoked on the main thread. The 1588c339a94Sopenharmony_ci callback receives the `ThreadSafeFunction`'s JavaScript callback function to 1598c339a94Sopenharmony_ci call as an `Napi::Function` in its parameters and the `DataType*` data pointer 1608c339a94Sopenharmony_ci (if provided). Must implement `void operator()(Napi::Env env, Function 1618c339a94Sopenharmony_ci jsCallback, DataType* data)`, skipping `data` if not provided. It is not 1628c339a94Sopenharmony_ci necessary to call into JavaScript via `MakeCallback()` because Node-API runs 1638c339a94Sopenharmony_ci `callback` in a context appropriate for callbacks. 1648c339a94Sopenharmony_ci 1658c339a94Sopenharmony_ci**These specific function overloads should only be used on a `ThreadSafeFunction` 1668c339a94Sopenharmony_cicreated via `ThreadSafeFunction(napi_threadsafe_function)`.** 1678c339a94Sopenharmony_ci 1688c339a94Sopenharmony_ci```cpp 1698c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::BlockingCall(void* data) const 1708c339a94Sopenharmony_ci 1718c339a94Sopenharmony_cinapi_status Napi::ThreadSafeFunction::NonBlockingCall(void* data) const 1728c339a94Sopenharmony_ci``` 1738c339a94Sopenharmony_ci- `data`: Data to pass to `call_js_cb` specified when creating the thread-safe 1748c339a94Sopenharmony_ci function via `napi_create_threadsafe_function`. 1758c339a94Sopenharmony_ci 1768c339a94Sopenharmony_ciReturns one of: 1778c339a94Sopenharmony_ci- `napi_ok`: The call was successfully added to the queue. 1788c339a94Sopenharmony_ci- `napi_queue_full`: The queue was full when trying to call in a non-blocking 1798c339a94Sopenharmony_ci method. 1808c339a94Sopenharmony_ci- `napi_closing`: The thread-safe function is aborted and cannot accept more 1818c339a94Sopenharmony_ci calls. 1828c339a94Sopenharmony_ci- `napi_invalid_arg`: The thread-safe function is closed. 1838c339a94Sopenharmony_ci- `napi_generic_failure`: A generic error occurred when attempting to add to the 1848c339a94Sopenharmony_ci queue. 1858c339a94Sopenharmony_ci 1868c339a94Sopenharmony_ci## Example 1878c339a94Sopenharmony_ci 1888c339a94Sopenharmony_ci```cpp 1898c339a94Sopenharmony_ci#include <chrono> 1908c339a94Sopenharmony_ci#include <thread> 1918c339a94Sopenharmony_ci#include <napi.h> 1928c339a94Sopenharmony_ci 1938c339a94Sopenharmony_ciusing namespace Napi; 1948c339a94Sopenharmony_ci 1958c339a94Sopenharmony_cistd::thread nativeThread; 1968c339a94Sopenharmony_ciThreadSafeFunction tsfn; 1978c339a94Sopenharmony_ci 1988c339a94Sopenharmony_ciValue Start( const CallbackInfo& info ) 1998c339a94Sopenharmony_ci{ 2008c339a94Sopenharmony_ci Napi::Env env = info.Env(); 2018c339a94Sopenharmony_ci 2028c339a94Sopenharmony_ci if ( info.Length() < 2 ) 2038c339a94Sopenharmony_ci { 2048c339a94Sopenharmony_ci throw TypeError::New( env, "Expected two arguments" ); 2058c339a94Sopenharmony_ci } 2068c339a94Sopenharmony_ci else if ( !info[0].IsFunction() ) 2078c339a94Sopenharmony_ci { 2088c339a94Sopenharmony_ci throw TypeError::New( env, "Expected first arg to be function" ); 2098c339a94Sopenharmony_ci } 2108c339a94Sopenharmony_ci else if ( !info[1].IsNumber() ) 2118c339a94Sopenharmony_ci { 2128c339a94Sopenharmony_ci throw TypeError::New( env, "Expected second arg to be number" ); 2138c339a94Sopenharmony_ci } 2148c339a94Sopenharmony_ci 2158c339a94Sopenharmony_ci int count = info[1].As<Number>().Int32Value(); 2168c339a94Sopenharmony_ci 2178c339a94Sopenharmony_ci // Create a ThreadSafeFunction 2188c339a94Sopenharmony_ci tsfn = ThreadSafeFunction::New( 2198c339a94Sopenharmony_ci env, 2208c339a94Sopenharmony_ci info[0].As<Function>(), // JavaScript function called asynchronously 2218c339a94Sopenharmony_ci "Resource Name", // Name 2228c339a94Sopenharmony_ci 0, // Unlimited queue 2238c339a94Sopenharmony_ci 1, // Only one thread will use this initially 2248c339a94Sopenharmony_ci []( Napi::Env ) { // Finalizer used to clean threads up 2258c339a94Sopenharmony_ci nativeThread.join(); 2268c339a94Sopenharmony_ci } ); 2278c339a94Sopenharmony_ci 2288c339a94Sopenharmony_ci // Create a native thread 2298c339a94Sopenharmony_ci nativeThread = std::thread( [count] { 2308c339a94Sopenharmony_ci auto callback = []( Napi::Env env, Function jsCallback, int* value ) { 2318c339a94Sopenharmony_ci // Transform native data into JS data, passing it to the provided 2328c339a94Sopenharmony_ci // `jsCallback` -- the TSFN's JavaScript function. 2338c339a94Sopenharmony_ci jsCallback.Call( {Number::New( env, *value )} ); 2348c339a94Sopenharmony_ci 2358c339a94Sopenharmony_ci // We're finished with the data. 2368c339a94Sopenharmony_ci delete value; 2378c339a94Sopenharmony_ci }; 2388c339a94Sopenharmony_ci 2398c339a94Sopenharmony_ci for ( int i = 0; i < count; i++ ) 2408c339a94Sopenharmony_ci { 2418c339a94Sopenharmony_ci // Create new data 2428c339a94Sopenharmony_ci int* value = new int( clock() ); 2438c339a94Sopenharmony_ci 2448c339a94Sopenharmony_ci // Perform a blocking call 2458c339a94Sopenharmony_ci napi_status status = tsfn.BlockingCall( value, callback ); 2468c339a94Sopenharmony_ci if ( status != napi_ok ) 2478c339a94Sopenharmony_ci { 2488c339a94Sopenharmony_ci // Handle error 2498c339a94Sopenharmony_ci break; 2508c339a94Sopenharmony_ci } 2518c339a94Sopenharmony_ci 2528c339a94Sopenharmony_ci std::this_thread::sleep_for( std::chrono::seconds( 1 ) ); 2538c339a94Sopenharmony_ci } 2548c339a94Sopenharmony_ci 2558c339a94Sopenharmony_ci // Release the thread-safe function 2568c339a94Sopenharmony_ci tsfn.Release(); 2578c339a94Sopenharmony_ci } ); 2588c339a94Sopenharmony_ci 2598c339a94Sopenharmony_ci return Boolean::New(env, true); 2608c339a94Sopenharmony_ci} 2618c339a94Sopenharmony_ci 2628c339a94Sopenharmony_ciNapi::Object Init( Napi::Env env, Object exports ) 2638c339a94Sopenharmony_ci{ 2648c339a94Sopenharmony_ci exports.Set( "start", Function::New( env, Start ) ); 2658c339a94Sopenharmony_ci return exports; 2668c339a94Sopenharmony_ci} 2678c339a94Sopenharmony_ci 2688c339a94Sopenharmony_ciNODE_API_MODULE( clock, Init ) 2698c339a94Sopenharmony_ci``` 2708c339a94Sopenharmony_ci 2718c339a94Sopenharmony_ciThe above code can be used from JavaScript as follows: 2728c339a94Sopenharmony_ci 2738c339a94Sopenharmony_ci```js 2748c339a94Sopenharmony_ciconst { start } = require('bindings')('clock'); 2758c339a94Sopenharmony_ci 2768c339a94Sopenharmony_cistart(function () { 2778c339a94Sopenharmony_ci console.log("JavaScript callback called with arguments", Array.from(arguments)); 2788c339a94Sopenharmony_ci}, 5); 2798c339a94Sopenharmony_ci``` 2808c339a94Sopenharmony_ci 2818c339a94Sopenharmony_ciWhen executed, the output will show the value of `clock()` five times at one 2828c339a94Sopenharmony_cisecond intervals: 2838c339a94Sopenharmony_ci 2848c339a94Sopenharmony_ci``` 2858c339a94Sopenharmony_ciJavaScript callback called with arguments [ 84745 ] 2868c339a94Sopenharmony_ciJavaScript callback called with arguments [ 103211 ] 2878c339a94Sopenharmony_ciJavaScript callback called with arguments [ 104516 ] 2888c339a94Sopenharmony_ciJavaScript callback called with arguments [ 105104 ] 2898c339a94Sopenharmony_ciJavaScript callback called with arguments [ 105691 ] 2908c339a94Sopenharmony_ci``` 291