iOS上的c ++,如何将抽象类型变量移动到线程中?

Posted

技术标签:

【中文标题】iOS上的c ++,如何将抽象类型变量移动到线程中?【英文标题】:c++ on iOS, how to move abstract type variable into thread? 【发布时间】: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(运行时)对象移动/共享到线程中的语义。

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

【问题讨论】:

【参考方案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++ 世界之间的整个通信是由复活的库完成的......

以上是关于iOS上的c ++,如何将抽象类型变量移动到线程中?的主要内容,如果未能解决你的问题,请参考以下文章

如何将C / C ++库代码封装为可在具有多个实例的单独线程中运行?

在C中添加不同类型的变量

如何将 android 工具添加到我在 mac 上的路径中? [复制]

Anylogic:如何将单选按钮链接到 double 类型的变量?

C语言中如何将double型数据转换为数组?

如何通知尾部更新到 C++ 窗口中的线程? [读取全局变量的未缓存值]