Last active
July 18, 2019 04:02
-
-
Save RomiTT/f56f8d30a756c022170faefd42b845c4 to your computer and use it in GitHub Desktop.
For thread-safe function call in native node module.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Napi::Value FGM::test(const Napi::CallbackInfo &info) { | |
Napi::Env env = info.Env(); | |
auto cb = info[0].As<Napi::Function>(); | |
threadSafeCallback = ThreadSafeFunction::Create(cb); | |
std::thread t([threadSafeCallback]() => { | |
// do something | |
// call thread-safe callback | |
threadSafeCallback->Call(_callbackStarted, [](napi_env env) { | |
// make a callback argument (Object, String, Array, Number ...) | |
auto obj = Napi::Object::New(env); | |
obj.Set("name", "Romi"); | |
obj.Set("age", 30); | |
// return the argument. | |
return obj; | |
}); | |
}); | |
t.deatch(); | |
return env.Undefined(); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
test((arg) => { | |
console.log("name: ", arg.name); | |
console.log("age: ", arg.age); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "ThreadSafeFunction.h" | |
#include <assert.h> | |
class JsArgument { | |
std::shared_ptr<ThreadSafeFunction> _owner; | |
ThreadSafeFunction::GetValueFunction _fGetValue; | |
public: | |
JsArgument(std::shared_ptr<ThreadSafeFunction> owner, ThreadSafeFunction::GetValueFunction fGetValue) | |
: _owner(owner) | |
, _fGetValue(std::move(fGetValue)) {} | |
Napi::Value GetArgument(napi_env env) { | |
return _fGetValue(env); | |
} | |
void Destory() { delete this; }; | |
}; | |
ThreadSafeFunction::ThreadSafeFunction(const Napi::Function& callback) { | |
_env = callback.Env(); | |
_callback = static_cast<napi_value>(callback); | |
_callbackRef = Napi::Persistent(callback); | |
napi_value work_name; | |
assert(napi_create_string_utf8(_env, "N-API Thread-safe Call from ThreadSafeFunction class", NAPI_AUTO_LENGTH, &work_name) == napi_ok); | |
assert(napi_create_threadsafe_function(_env, _callback, NULL, work_name, 0, 1, NULL, NULL, NULL, CallJs, &_func) == napi_ok); | |
} | |
ThreadSafeFunction::~ThreadSafeFunction() { | |
Release(); | |
} | |
void ThreadSafeFunction::Acquire() { | |
assert(napi_acquire_threadsafe_function(_func) == napi_ok); | |
} | |
void ThreadSafeFunction::Release() { | |
assert(napi_release_threadsafe_function(_func, napi_tsfn_release) == napi_ok); | |
} | |
void ThreadSafeFunction::Call(std::shared_ptr<ThreadSafeFunction> owner, GetValueFunction f) { | |
assert(napi_call_threadsafe_function(_func, new JsArgument{owner, f}, napi_tsfn_blocking) == napi_ok); | |
} | |
std::shared_ptr<ThreadSafeFunction> ThreadSafeFunction::Create(const Napi::Function& callback) { | |
return std::shared_ptr<ThreadSafeFunction>(new ThreadSafeFunction(callback)); | |
} | |
void ThreadSafeFunction::CallJs(napi_env env, napi_value js_cb, void* context, void* data) { | |
(void)context; | |
JsArgument* jsArg = (JsArgument*)data; | |
if (env != NULL) { | |
Napi::Value argVal; | |
napi_value arg = (napi_value)jsArg->GetArgument(Napi::Env(env)); | |
napi_value undefined; | |
// Retrieve the JavaScript `undefined` value so we can use it as the `this` | |
// value of the JavaScript function call. | |
assert(napi_get_undefined(env, &undefined) == napi_ok); | |
// Call the JavaScript function and pass it the prime that the secondary | |
// thread found. | |
assert(napi_call_function(env, | |
undefined, | |
js_cb, | |
1, | |
(arg == NULL) ? NULL : &arg, | |
NULL) == napi_ok); | |
} | |
jsArg->Destory(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#ifndef __THREAD_SAFE_FUNCTION_H__ | |
#define __THREAD_SAFE_FUNCTION_H__ | |
#include <napi.h> | |
#include <functional> | |
#include <memory> | |
class ThreadSafeFunction { | |
public: | |
typedef std::function<Napi::Value(napi_env)> GetValueFunction; | |
private: | |
napi_threadsafe_function _func; | |
napi_env _env; | |
napi_value _callback; | |
Napi::FunctionReference _callbackRef; | |
private: | |
ThreadSafeFunction(const Napi::Function& callback); | |
public: | |
~ThreadSafeFunction(); | |
void Acquire(); | |
void Release(); | |
void Call(std::shared_ptr<ThreadSafeFunction> owner, GetValueFunction f); | |
static std::shared_ptr<ThreadSafeFunction> Create(const Napi::Function& callback); | |
private: | |
static void CallJs(napi_env env, napi_value js_cb, void* context, void* data); | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment