这个范围的线程代码是否可以更改为使用`FnOnce()`而不是`Box <fnonce()>`?

时间:2016-10-14 16:50:09

标签: rust

我有以下代码在Rust中实现作用域线程 - 也就是说,能够生成线程并安全地访问堆栈中的变量。以下大部分代码均来自crossbeam,其中一些灵感来自scoped_threadpool

use std::thread;
use std::thread::JoinHandle;
use std::collections::LinkedList;
use std::marker::PhantomData;
use std::boxed::Box;

pub struct Scope<'a> {
    join_handles: LinkedList<JoinHandle<()>>,
    _marker: PhantomData<::std::cell::Cell<&'a mut ()>>
}

impl<'a> Scope<'a> {
    pub fn spawn<F>(&mut self, f: F) where F: FnOnce() + Send + 'a {
        // Could this be done without using a Box?
        let closure: Box<FnBox + Send + 'a> = Box::new(f);
        let closure: Box<FnBox + Send + 'static> = unsafe{
            std::mem::transmute(closure)
        };
        let join_handle = thread::spawn(move || closure.call_box());
        self.join_handles.push_back(join_handle);
    }
}

pub fn scope<'a, F, R>(f: F) -> R where F: FnOnce(&mut Scope<'a>) ->     R {
    let mut scope = Scope {
        join_handles: LinkedList::new(),
        _marker: PhantomData
    };
    let ret = f(&mut scope);
    for join_handle in scope.join_handles {
        join_handle.join().unwrap();
    }
    ret
}

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<Self>) { (*self)() }
}

// Example usage:

// let mut foo = 0;
// scope(|mut scope| {
//     scope.spawn(|| {
//         foo = 1;
//     });
// });
// assert!(foo == 1);

是否可以更改spawn函数,以便f不放在Box中,以避免额外的堆分配?如果没有,为什么有必要使用Box

1 个答案:

答案 0 :(得分:1)

据我所知,从Rust 1.12开始,这是不可能的。我们必须将 <?php $result = imagecreatefromstring($data); imagejpeg($result,'test.jpg'); ?> 转换为另一种与f边界相同的大小。最直接的方法是将其转换为与'static大小相同的字节数组,但这是不可能的,因为我们无法使用size_of一个常量表达式(就像我们在C ++中使用F一样)。

我们可以通过分配一个独立于sizeof的固定大小的数组来解决此问题,如果F太大或者回退到使用F,则会发生混乱。

Box