WebAssembly并发场景下C/C++修改栈指针实现线程安全栈隔离
WebAssembly共享内存场景下C++可重入函数独立栈实现方案
问题背景
可重入C++函数编译为Wasm后,使用导入的共享内存时存在线程安全问题:函数运行使用的栈被分配在共享线性内存的硬编码固定位置,多个WebWorker上的同模块实例并行执行时会出现栈数据互相覆盖的竞争问题。
前置约束
- 不引入wasi-libc、emscripten这类过重的依赖
- 自行承担WebAssembly多线程特性尚未完全成熟带来的崩溃、数据竞争风险
- 核心目标为每个线程实例分配非重叠的独立栈,解决栈竞争导致的线程安全问题
直接修改栈指针的报错问题
尝试通过C侧声明extern unsigned char __stack_pointer;直接修改栈指针时,wasm-ld会抛出符号类型不匹配错误:
wasm-ld内部将
__stack_pointer定义为WASM_SYMBOL_TYPE_GLOBAL类型,而C侧声明生成的目标文件中该符号被定义为WASM_SYMBOL_TYPE_DATA类型,无法完成链接。
最终解决方案
通过新增Wasm汇编文件定义栈指针修改函数的方式解决符号类型不匹配问题:
- 新增
stack_helper.wat汇编文件,内容如下:
(module (import "env" "__stack_pointer" (global $stack_ptr (mut i32))) (func (export "init_stack") (param i32) local.get 0 global.set $stack_ptr ) )
- 将该汇编文件和你的C/C++业务代码一同编译、链接为最终的Wasm模块
使用步骤
- 为每个WebWorker预分配一块不与其他线程重叠的内存段作为独立栈,栈大小可根据业务场景自行调整
- 实例化Wasm模块后,优先调用导出的
init_stack方法,传入分配的栈内存的高地址(适配Wasm栈向下增长的特性) - 后续执行C++可重入函数时,所有栈操作都会落在当前实例的独立栈区间内,不会出现多线程栈数据竞争问题
内容的提问来源于stack exchange,提问作者spaghetti
相关产品推荐
相关产品推荐

