< 返回版块

aircloud 发表于 2019-12-13 12:20

Tags:rust, Webassembly

我在使用 rust + WebAssembly 开发的时候遇到了一个死锁问题

目前由于用到了一些全局访问的变量,我选择了 lazy_static (使用 thread_local 回调式的写法可能会造成嵌套问题)和 mutex,但我目前遇到了一个问题:

目前我在 rust 中声明了很多函数,通过 #[wasm_bindgen] 的方式供 js 调用,它们会读写一些 lazy_static 的变量

当其中的一个函数 panic 之后,对 mutex 的持有无法释放,导致其他函数如果需要用到这个 mutex,也会 panic

当然我知道 panic 的问题是意外的,并且需要修复的,但是实际上这些函数彼此比较独立,读写的 lazy_static 变量虽然有相交,但实际上某一处 bug 不一定会影响其他造成 bug

我的诉求是有没有一种方式,在 wasm 中 rust panic 之后触发释放 mutex,这样其他函数的调用会是正常的。

或者对于这类问题,有没有什么更好的实践?

谢谢~!

增加demo:

js:

const js = import("../pkg/hello_wasm.js");
js.then(js => {
  window.js = js;
  console.log(js.get_index());
  js.add_index();
  console.log(js.get_index());
  js.add_index();
  console.log(js.get_index());
  js.add_index();
  console.log(js.get_index());
  js.add_index();
  console.log(js.get_index());
  js.add_index();
});

rust:

use std::{sync::Mutex};
use wasm_bindgen::prelude::*;
use std::sync::PoisonError;

pub struct CurrentStatus {
  pub index: i32,
}

impl CurrentStatus {
  fn new() -> Self {
    CurrentStatus {
      index: 1,
    }
  }
  fn get_index(&mut self) -> i32 {
    self.index += 1;
    self.index.clone()
  }

  fn add_index(&mut self) {
    self.index += 2;
  }
}

lazy_static! {
    pub static ref FOO: Mutex<CurrentStatus> = Mutex::new(CurrentStatus::new());
}

unsafe impl Send for CurrentStatus {}

#[wasm_bindgen]
pub fn add_index() {
  FOO.lock().unwrap_or_else(PoisonError::into_inner).add_index();
}

#[wasm_bindgen]
pub fn get_index() -> i32 {
  let mut foo = FOO.lock().unwrap_or_else(PoisonError::into_inner);
  if foo.get_index() == 6 {
    panic!();
  }
  return foo.get_index();
}

panic 之后,再也无法调用成功。。

评论区

写评论
yooocen 2019-12-17 18:10

能放点源码看看吗?

pfcoder 2019-12-13 16:05

听起来是想从panic中恢复? 可以考虑用 std::panic::catch_unwind 把需要特殊处理的panic! wrap一下

类似如下代码: use std::panic;

let result = panic::catch_unwind(|| {
    panic!("error happen!"); // original panic! code
});
if result.is_err() {
    // panic happens, do some release job, then panic again
    // relase mutex
    panic!("thread exit now");
} else {
    println!("contunue");
}

不过这样比较啰嗦,panic!应该会触发drop, 在drop中做清理工作应该也可以

1 共 2 条评论, 1 页