如何将本机空指针传递到Dart隔离-无需复制?

如何将本机空指针传递到Dart隔离-无需复制?,dart,dart-isolates,dart-ffi,Dart,Dart Isolates,Dart Ffi,我正在为Dart公开一个音频库(C库)。要触发音频引擎,它需要几个初始化步骤(UI不阻塞),然后使用执行函数触发音频处理,这就是阻塞(音频处理是一项繁重的任务)。这就是我来读Dart分离物的原因 我的第一个想法是,我只需要在隔离中调用performance方法,但这似乎是不可能的,因为perform函数将引擎状态作为第一个参数-这个引擎状态是一个不透明的指针(dart:ffi中的指针)。当尝试使用compute函数将引擎状态传递给新的隔离时,Dart VM返回一个错误-它无法将C指针传递给隔离

我正在为Dart公开一个音频库(C库)。要触发音频引擎,它需要几个初始化步骤(UI不阻塞),然后使用执行函数触发音频处理,这就是阻塞(音频处理是一项繁重的任务)。这就是我来读Dart分离物的原因

我的第一个想法是,我只需要在隔离中调用performance方法,但这似乎是不可能的,因为perform函数将引擎状态作为第一个参数-这个引擎状态是一个不透明的指针(dart:ffi中的指针)。当尝试使用compute函数将引擎状态传递给新的隔离时,Dart VM返回一个错误-它无法将C指针传递给隔离

我找不到一种方法将这些数据传递到隔离区,我认为这是由于主隔离区和我正在创建的隔离区的内存不同

因此,我可能应该在隔离中管理整个发动机状态,这意味着:

  • 创建引擎状态
  • 使用一些选项(字符串)初始化它
  • 触发执行功能
  • 在运行时控制音频
我找不到任何关于如何在隔离中执行此操作的示例,但从主线程/隔离触发。关于如何管理隔离内存(保持引擎状态并使用它),两者都不重要。我当然可以

以下是我想做的一个非孤立的例子:

指针engineState=createEngineState();
initEngine(engineState,参数字符串);
startEngine(房地产);
表演(不动产);
在运行时,由UI操作(如滑块值更改或按钮单击)触发:

setEngineControl(engineState,valueToSet);
双重控制值=getEngineControl(engineState);
引擎状态可以封装在一个类中,我认为它在这里并不重要。 无论它是一个类还是一个不透明的数据类型,我都找不到如何管理和保持这种状态,以及如何从主线程执行触发器(在隔离中处理)。有什么想法吗

提前,谢谢

PS:我注意到,在写作时,我的问题/解释可能不准确,我不得不说我在这里有点迷茫,因为我从未使用过Dart。如果缺少一些信息,请告诉我

4月24日编辑: 它似乎在隔离内部创建和管理对象状态。但主要问题并没有解决。因为perform方法在未完成时实际上是阻塞的,所以无法在隔离中仍然接收消息。 我首先想到的一个选项是使用performBlock方法,它只执行一块音频样本。像这样:

while(performBlock(engineState)){
//听留言,做点什么
}
但这似乎不起作用,这个过程仍然被阻止,直到音频性能完成。即使在隔离中的异步方法中调用此循环,它也会阻塞,并且不会读取任何消息

我现在考虑将主隔离中管理的
指针
传递给另一个的可能性,该指针将是工作者(仅用于执行方法),然后能够从主隔离触发一些控制方法

Dart包提供了一个注册表子库来管理一些共享内存。但仍然不可能在隔离之间传递void指针

[错误:flatter/lib/ui/ui_dart_state.cc(157)]未处理的异常:无效参数:无法在隔离之间传递本机对象(来自dart:ffi),例如指针和结构


有没有人遇到过这种情况

可以获取此
指针作为数字指向的地址,并从此地址构造新的
指针(请参阅和)。因为数字可以在隔离之间自由传递,所以这可以用来在它们之间传递本机指针

例如,在您的例子中,可以这样做(我使用颤振使示例更简单,但显然也可以显式使用
Send/ReceivePort
s)

//要在回退隔离中使用的回调。
//返回新引擎的地址。
int initEngine(字符串参数){
指针engineState=createEngineState();
初始化引擎(引擎状态、参数);
startEngine(房地产);
返回。地址;
}
//要在回退隔离中使用的回调。
//使用给定的引擎执行任何需要的处理。
无效进程WithEngine(int engineStateAddress){
最终engineState=指针.fromAddress(engineStateAddress);
工艺(不动产);
}
void main(){
//在后台隔离中初始化引擎。
最终地址=计算(initEngine,“参数”);
final engineState=指针.fromAddress(地址);
//使用引擎在背景隔离中执行一些繁重的计算。
计算(processWithEngine、engineState.address);
}

我最终在音频循环本身内部处理回调

while(performAudio())
{
tasks.forEach((字符串键,列表值){
double val=getCallback(键);
value.forEach((int元素){
发送([element,val]);
});
});
}
其中“val”是要发送给回调的对象。int'value'的列表是回调索引的列表

假设音频循环使用512个样本的向量大小执行,则在处理每512个音频样本后,您将能够通过回调,这意味着每秒48000/512次(假设采样率为48000)。这种方法不是最好的,但它很有效,不过我还是要看看它在非常密集的处理环境中是否有效。在这里,它被认为是用于实时音频,但它也可以用于音频渲染


您可以在这里看到完整的代码:

您不能只做整个过程吗?(创建指针,并与主控制器通信