【问题标题】:c++ on iOS, how to move abstract type variable into thread?iOS上的c ++,如何将抽象类型变量移动到线程中?
【发布时间】:2021-06-05 09:56:26
【问题描述】:

我正在尝试使用新的 JSI 绑定为 react-native 创建一个 SQLite 库/适配器。 JSI 绑定只是 Javascript Core(还有 hermes 和 V8?)之上的一层,它允许直接从 javascript 调用 c++。

对于我的问题而言,有很多代码不是很重要,但基本上,同步调用工作正常,但现在我正在尝试创建一个线程来执行异步工作,然后解决一个 javascript 承诺。

在下面的代码中,我创建并返回了一个 Promise,然后尝试生成一个线程来执行后台工作。

    auto asyncExecSQL = jsi::Function::createFromHostFunction(
      rt,
      jsi::PropNameID::forAscii(rt, "sequel_asyncExecSQL"),
      1,
      [](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
        jsi::Value promise = rt.global().getPropertyAsFunction(rt, "Promise").callAsConstructor(
          rt,
          jsi::Function::createFromHostFunction(
                                                rt,
                                                jsi::PropNameID::forAscii(rt, "executor"),
                                                2,
                                                [](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t) -> jsi::Value {

            jsi::Function cb = args[0].asObject(rt).asFunction(rt);
            auto resolve = std::make_shared<jsi::Function>(std::move(cb));

            thread t1([rt, resolve] { // ERROR: By-copy capture of value of abstract type 'jsi::Runtime'
                resolve->call(rt, jsi::Value(42));
            });


            return {};
        }));

        return promise;
    });

    rt.global().setProperty(rt, "sequel_asyncExecSQL", move(asyncExecSQL));

你可以或多或少地忽略所有的 jsi:: mumbo-jumbo,它更少地从 c++ 端操作 javascript 对象。可以看到Runtime对象很重要,需要它来操作和创建对象。

问题是,我正在尝试创建一个线程来在后台执行获取代码,我不知道将rt(运行时)对象移动/共享到线程中的语义。

谁能向我解释我做错了什么?

【问题讨论】:

    标签: javascript c++ ios multithreading


    【解决方案1】:

    设法让它工作:

        auto asyncExecSQL = jsi::Function::createFromHostFunction(
          rt,
          jsi::PropNameID::forAscii(rt, "sequel_asyncExecSQL"),
          1,
          [](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t count) -> jsi::Value {
    
            string query = args[0].asString(rt).utf8(rt);
    
            jsi::Value promise = rt.global().getPropertyAsFunction(rt, "Promise").callAsConstructor(
              rt,
              jsi::Function::createFromHostFunction(
                                                    rt,
                                                    jsi::PropNameID::forAscii(rt, "executor"),
                                                    2,
                                                    [query](jsi::Runtime &rt, const jsi::Value &thisValue, const jsi::Value *args, size_t) -> jsi::Value {
    
                thread t1([&rt, &query, resolve{ std::make_shared<jsi::Value>(rt, args[0]) }] {
                    cout << "Trying to exec" << query << endl;
                    vector<jsi::Object> results = sequel_execute(rt, query);
    
                    auto res = jsi::Array(rt, results.size());
                    for(int i = 0; i < results.size(); i++) {
                        res.setValueAtIndex(rt, i, move(results[i]));
                    }
    
                    resolve->asObject(rt).asFunction(rt).call(rt, res);
                });
    
                t1.detach();
    
    
                return {};
            }));
    
            return promise;
        });
    

    【讨论】:

    • 正是我想要的。顺便说一句,很棒的博客!希望一旦 turbomodules 正式发布,我们会得到一些不错的文档。
    • 由于某些原因在android上虽然当promise被解析时RN线程不会自动更新:即,一旦在c ++端调用resolve函数,就不会触发像§...().then((value) =&gt; setState(value))这样的事情。它仅在重新渲染 ui 时触发。它在 ios 上按预期工作。
    • 其实在ios上加this_thread::sleep(2s)也很明显
    • 你最好从 msrousavy 研究 react-native-mmvk 或 react-native-background-task,他以不同的方式实现后台任务
    • 是的,我浏览了他的仓库。当他从复活的地方导入代码时,他失去了我。所以他的代码只是创建了一个执行器,但是 react 和 c++ 世界之间的整个通信是由复活的库完成的......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    • 1970-01-01
    • 2011-03-19
    • 2015-06-09
    • 2012-01-02
    • 1970-01-01
    相关资源
    最近更新 更多