【问题标题】:Threaded code crashes calling FFI process线程代码崩溃调用 FFI 进程
【发布时间】:2015-06-30 21:54:15
【问题描述】:

我已将函数转换为使用线程(根据this answer)。它在测试中的行为符合预期(即,它向非线程版本返回相同的值)。但是,使用 ctypes 从 Python 调用它会导致调用进程崩溃。

一、工作功能:

#[no_mangle]
pub extern fn convert_vec(lon: Array, lat: Array) -> Array {
    // snip
    // orig is a Vec<(f32, f32)>
    // convert is a conversion function
    let result: Vec<(i32, i32)> = orig.iter()
        .map(|elem| convert(elem.0, elem.1))
        .collect();
    // convert back to vector of unsigned integer Tuples
    let nvec = result.iter()
        .map(|ints| Tuple { a: ints.0 as u32, b: ints.1 as u32 })
        .collect();
    Array::from_vec(nvec)
}

现在是线程版本,它通过了测试(使用 cargo test)但在从 Python 调用时崩溃:

#[no_mangle]
pub extern fn convert_vec_threaded(lon: Array, lat: Array) -> Array {
    // snip
    // orig is a Vec<(f32, f32)>
    // convert is a conversion function
    let mut guards: Vec<JoinHandle<Vec<(i32, i32)>>> = vec!();
    // split into slices
    for chunk in orig.chunks(orig.len() / NUMTHREADS as usize) {
        let chunk = chunk.to_owned();
        let g = thread::spawn(move || chunk
            .into_iter()
            .map(|elem| convert(elem.0, elem.1))
            .collect());
        guards.push(g);
    }
    let mut result: Vec<(i32, i32)> = Vec::with_capacity(orig.len());
    for g in guards {
        result.extend(g.join().unwrap().into_iter());
    }
    // convert back to vector of unsigned integer Tuples
    let nvec = result.iter()
        .map(|ints| Tuple { a: ints.0 as u32, b: ints.1 as u32 })
        .collect();
    Array::from_vec(nvec)
}

完整的可测试示例可用here

【问题讨论】:

  • 崩溃是什么样子的?我不会使用 .unwrap(),因为来自 Python 的调用中的 rust panic 是一个非常糟糕的主意
  • 我在 ipython 中遇到的崩溃是:thread '&lt;unnamed&gt;' panicked at 'assertion failed: size != 0', /private/tmp/rust20150626-13301-uiklsd/rustc-1.1.0/src/libcore/slice.rs:196 fatal runtime error: Could not unwind stack, error = 5 Illegal instruction: 4
  • 好吧,这个断言看起来你实际上是在传递.chunks(0)。就这么简单吗?
  • 我没听懂……你的意思是我是在传递一个零大小的块吗?
  • .chunks(orig.len() / NUMTHREADS as usize) ← 参数不能为零

标签: python multithreading rust ffi


【解决方案1】:

从错误消息看来,您对某些输入使用了 0 的块大小。 [T]::chunks(size) 将断言 size != 0

如果我们想要NUMTHREADS 块,我们可以这样拆分它:

// Divide into NUMTHREADS chunks
let mut size = orig.len() / NUMTHREADS;
if orig.len() % NUMTHREADS > 0 { size += 1; }
// If we want to avoid the case where orig.len() == 0, we need another adjustment:
size = std::cmp::max(1, size);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多