Add docs for thread::spawn()

master
WangRunji 6 years ago
parent 7dd9494389
commit fc2fd18c36

@ -73,34 +73,61 @@ impl<S: ThreadSupport> ThreadMod<S> {
}
/// Spawns a new thread, returning a JoinHandle for it.
///
/// `F`: Type of the function `f`
/// `T`: Type of the return value of `f`
pub fn spawn<F, T>(f: F) -> JoinHandle<S, T>
where
F: Send + 'static + FnOnce() -> T,
T: Send + 'static,
{
info!("spawn:");
// 注意到下面的问题:
// Processor只能从入口地址entry+参数arg创建新线程
// 而我们现在需要让它执行一个未知类型的闭包函数f
// 首先把函数本体(代码数据)置于堆空间中
let f = Box::into_raw(Box::new(f));
let pid = S::processor().add(Context::new_kernel(kernel_thread_entry::<S, F, T>, f as usize));
return JoinHandle {
thread: Thread { pid, mark: PhantomData },
mark: PhantomData,
};
// 定义一个静态函数作为新线程的入口点
// 其参数是函数f在堆上的指针
// 这样我们就把函数f传到了一个静态函数内部
//
// 注意到它具有泛型参数因此对每一次spawn调用
// 由于F类型是独特的因此都会生成一个新的kernel_thread_entry
extern fn kernel_thread_entry<S, F, T>(f: usize) -> !
where
S: ThreadSupport,
F: Send + 'static + FnOnce() -> T,
T: Send + 'static,
{
// 在静态函数内部:
// 根据传进来的指针恢复f
let f = unsafe { Box::from_raw(f as *mut F) };
// 调用f并将其返回值也放在堆上
let ret = Box::new(f());
// unsafe { LocalKey::<usize>::get_map() }.clear();
// 清理本地线程存储
// unsafe { LocalKey::<usize>::get_map() }.clear();
// 让Processor退出当前线程
// 把f返回值在堆上的指针以线程返回码的形式传递出去
let mut processor = S::processor();
let pid = processor.current_pid();
processor.exit(pid, Box::into_raw(ret) as usize);
processor.schedule();
// 再也不会被调度回来了
unreachable!()
}
// 在Processor中创建新的线程
let pid = S::processor().add(Context::new_kernel(kernel_thread_entry::<S, F, T>, f as usize));
// 接下来看看`JoinHandle::join()`的实现
// 了解是如何获取f返回值的
return JoinHandle {
thread: Thread { pid, mark: PhantomData },
mark: PhantomData,
};
}
/// Cooperatively gives up a timeslice to the OS scheduler.
@ -155,6 +182,7 @@ impl<S: ThreadSupport, T> JoinHandle<S, T> {
let mut processor = S::processor();
match processor.current_wait_for(self.thread.pid) {
WaitResult::Ok(_, exit_code) => unsafe {
// Find return value on the heap from the exit code.
Ok(*Box::from_raw(exit_code as *mut T))
}
WaitResult::NotExist => Err(()),

Loading…
Cancel
Save