Appearance
源码:labs/dart/host/bin/runtime_concurrency/ffi_demo.dart
- 原始路径:
labs/dart/host/bin/runtime_concurrency/ffi_demo.dart - 类型:
dart
dart
// dart:ffi 零拷贝与原生函数调用演示(纯 dart:ffi,零外部依赖)
//
// 对应 docs 05-bridge-hybrid/06-native-thread-isolate-bridge.md:
// 1. DynamicLibrary.process() 拿进程符号表,lookup 原生函数
// 2. NativeFunction / Pointer / 类型映射(Int32/IntPtr/Void/Uint8)
// 3. malloc + asTypedList:Dart 直接读写 Native 内存(零拷贝)
// 4. 对照:FFI 无序列化开销 vs PlatformChannel 需切主线程 + 拷贝
//
// 运行:dart run bin/runtime_concurrency/ffi_demo.dart
import 'dart:ffi';
// C 函数签名声明(等价于 C 头文件里的函数原型)
typedef CGetpidNative = Int32 Function();
typedef CGetpidDart = int Function();
typedef CMallocNative = Pointer<Void> Function(IntPtr);
typedef CMallocDart = Pointer<Void> Function(int);
typedef CFreeNative = Void Function(Pointer<Void>);
typedef CFreeDart = void Function(Pointer<Void>);
void main() {
// 1. 拿当前进程符号表(libc 的 malloc/free/getpid 都在)
final libc = DynamicLibrary.process();
print('=== 1. 调用 C 标准库函数 ===');
final getpid = libc.lookupFunction<CGetpidNative, CGetpidDart>('getpid');
print(' getpid() = ${getpid()}(Dart 直接调用 C 函数)');
final malloc = libc.lookupFunction<CMallocNative, CMallocDart>('malloc');
final free = libc.lookupFunction<CFreeNative, CFreeDart>('free');
print('');
print('=== 2. malloc + asTypedList:零拷贝读写 Native 内存 ===');
final count = 8;
final ptr = malloc(sizeOf<IntPtr>() * count).cast<Uint8>();
// asTypedList:把 Native 内存包装成 Dart TypedData 视图(零拷贝,无复制)
final view = ptr.asTypedList(count);
for (var i = 0; i < count; i++) {
view[i] = (i * 10); // 直接写 Native 内存
}
print(' 通过 Dart 视图写入并读回: $view');
print(' 指针地址: 0x${ptr.address.toRadixString(16)}(C 堆上的真实地址)');
// C 侧与 Dart 侧看到的是同一块内存(零拷贝语义)
view[0] = 255;
print(' 修改后再次读回(同一块内存,无拷贝): ${ptr.asTypedList(count)[0]}');
free(ptr.cast()); // 释放 Native 内存(必须,否则泄漏)
print('');
print('=== 3. 结论 ===');
print(' dart:ffi 直接操作 Native 指针(Pointer<T>),无序列化/拷贝开销;');
print(' 对应 PlatformChannel 每次调用都要内存序列化 + 切主线程。');
print(' 注意:C++ 后台线程回调 Dart 仍须 Dart_PostCObject(见 docs 06)。');
}