flow like the river
This commit is contained in:
commit
013fe673f3
42435 changed files with 5764238 additions and 0 deletions
303
BACK_BACK/node_modules/node-addon-api/doc/threadsafe_function.md
generated
vendored
Executable file
303
BACK_BACK/node_modules/node-addon-api/doc/threadsafe_function.md
generated
vendored
Executable file
|
|
@ -0,0 +1,303 @@
|
|||
# ThreadSafeFunction
|
||||
|
||||
JavaScript functions can normally only be called from a native addon's main
|
||||
thread. If an addon creates additional threads, then node-addon-api functions
|
||||
that require a `Napi::Env`, `Napi::Value`, or `Napi::Reference` must not be
|
||||
called from those threads.
|
||||
|
||||
When an addon has additional threads and JavaScript functions need to be invoked
|
||||
based on the processing completed by those threads, those threads must
|
||||
communicate with the addon's main thread so that the main thread can invoke the
|
||||
JavaScript function on their behalf. The thread-safe function APIs provide an
|
||||
easy way to do this.
|
||||
|
||||
These APIs provide the type `Napi::ThreadSafeFunction` as well as APIs to
|
||||
create, destroy, and call objects of this type.
|
||||
`Napi::ThreadSafeFunction::New()` creates a persistent reference that holds a
|
||||
JavaScript function which can be called from multiple threads. The calls happen
|
||||
asynchronously. This means that values with which the JavaScript callback is to
|
||||
be called will be placed in a queue, and, for each value in the queue, a call
|
||||
will eventually be made to the JavaScript function.
|
||||
|
||||
`Napi::ThreadSafeFunction` objects are destroyed when every thread which uses
|
||||
the object has called `Release()` or has received a return status of
|
||||
`napi_closing` in response to a call to `BlockingCall()` or `NonBlockingCall()`.
|
||||
The queue is emptied before the `Napi::ThreadSafeFunction` is destroyed. It is
|
||||
important that `Release()` be the last API call made in conjunction with a given
|
||||
`Napi::ThreadSafeFunction`, because after the call completes, there is no
|
||||
guarantee that the `Napi::ThreadSafeFunction` is still allocated. For the same
|
||||
reason it is also important that no more use be made of a thread-safe function
|
||||
after receiving a return value of `napi_closing` in response to a call to
|
||||
`BlockingCall()` or `NonBlockingCall()`. Data associated with the
|
||||
`Napi::ThreadSafeFunction` can be freed in its `Finalizer` callback which was
|
||||
passed to `ThreadSafeFunction::New()`.
|
||||
|
||||
Once the number of threads making use of a `Napi::ThreadSafeFunction` reaches
|
||||
zero, no further threads can start making use of it by calling `Acquire()`. In
|
||||
fact, all subsequent API calls associated with it, except `Release()`, will
|
||||
return an error value of `napi_closing`.
|
||||
|
||||
## Methods
|
||||
|
||||
### Constructor
|
||||
|
||||
Creates a new empty instance of `Napi::ThreadSafeFunction`.
|
||||
|
||||
```cpp
|
||||
Napi::Function::ThreadSafeFunction();
|
||||
```
|
||||
|
||||
### Constructor
|
||||
|
||||
Creates a new instance of the `Napi::ThreadSafeFunction` object.
|
||||
|
||||
```cpp
|
||||
Napi::ThreadSafeFunction::ThreadSafeFunction(napi_threadsafe_function tsfn);
|
||||
```
|
||||
|
||||
- `tsfn`: The `napi_threadsafe_function` which is a handle for an existing
|
||||
thread-safe function.
|
||||
|
||||
Returns a non-empty `Napi::ThreadSafeFunction` instance.
|
||||
|
||||
### New
|
||||
|
||||
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.
|
||||
|
||||
```cpp
|
||||
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 the
|
||||
`Napi::ThreadSafeFunction` object.
|
||||
- `callback`: The `Function` to call from another thread.
|
||||
- `[optional] resource`: An object associated with the async work that will be
|
||||
passed to possible async_hooks init hooks.
|
||||
- `resourceName`: A JavaScript string to provide an identifier for the kind of
|
||||
resource that is being provided for diagnostic information exposed by the
|
||||
async_hooks API.
|
||||
- `maxQueueSize`: Maximum size of the queue. `0` for no limit.
|
||||
- `initialThreadCount`: The initial number of threads, including the main
|
||||
thread, which will be making use of this function.
|
||||
- `[optional] context`: Data to attach to the resulting `ThreadSafeFunction`.
|
||||
- `[optional] finalizeCallback`: Function to call when the `ThreadSafeFunction`
|
||||
is being destroyed. This callback will be invoked on the main thread when the
|
||||
thread-safe function is about to be destroyed. It receives the context and the
|
||||
finalize data given during construction (if given), and provides an
|
||||
opportunity for cleaning up after the threads e.g. by calling
|
||||
`uv_thread_join()`. It is important that, aside from the main loop thread,
|
||||
there be no threads left using the thread-safe function after the finalize
|
||||
callback completes. Must implement `void operator()(Env env, DataType* data,
|
||||
Context* hint)`, skipping `data` or `hint` if they are not provided.
|
||||
Can be retreived via `GetContext()`.
|
||||
- `[optional] data`: Data to be passed to `finalizeCallback`.
|
||||
|
||||
Returns a non-empty `Napi::ThreadSafeFunction` instance.
|
||||
|
||||
### Acquire
|
||||
|
||||
Add a thread to this thread-safe function object, indicating that a new thread
|
||||
will start making use of the thread-safe function.
|
||||
|
||||
```cpp
|
||||
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()`.
|
||||
|
||||
### Release
|
||||
|
||||
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.
|
||||
|
||||
```cpp
|
||||
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 attemping to release
|
||||
the thread-safe function.
|
||||
|
||||
### Abort
|
||||
|
||||
"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` and
|
||||
`NonBlockingCall()` 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.
|
||||
|
||||
```cpp
|
||||
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 attemping to abort
|
||||
the thread-safe function.
|
||||
|
||||
### BlockingCall / NonBlockingCall
|
||||
|
||||
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()` and
|
||||
`NonBlockingCall()` for use with optional parameters: skip the optional
|
||||
parameter for that specific overload.
|
||||
|
||||
```cpp
|
||||
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. The
|
||||
callback receives the `ThreadSafeFunction`'s JavaScript callback function to
|
||||
call as an `Napi::Function` in its parameters and the `DataType*` data pointer
|
||||
(if provided). Must implement `void operator()(Napi::Env env, Function
|
||||
jsCallback, DataType* data)`, skipping `data` if not provided. It is not
|
||||
necessary to call into JavaScript via `MakeCallback()` because N-API runs
|
||||
`callback` in a context appropriate for callbacks.
|
||||
|
||||
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 attemping to add to the
|
||||
queue.
|
||||
|
||||
## Example
|
||||
|
||||
```cpp
|
||||
#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:
|
||||
|
||||
```js
|
||||
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 ]
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue