异步管理
异步指的是当前的请求不能立刻得到满足,需要等待一个事件,当事件发生时,才能继续往下执行。这里我们以一个异步系统调用为例进行说明:
#[no_mangle]
pub fn main() -> i32 {
let v = vec![
thread_create(thread_a as usize, 0),
thread_create(thread_b as usize, 0),
thread_create(thread_c as usize, 0),
];
for tid in v.iter() {
let exit_code = thread_join(*tid as usize);
println!("thread#{} exited with code {}", tid, exit_code);
}
println!("main thread exited");
0
}
这是一个用户态使用多线程的例子,可见主线程创建了三个线程,并在程序退出前等待所有子线程退出。
thread_join
最终在内核的实现如下:
/// 主线程等待tid线程
///
/// 若不是主线程调用,就报错并返回usize::MAX
pub fn sys_thread_join(tid: usize) -> (usize, usize) {
// 只允许主线程调用
....
if cur_tid != 0 {
println!(
"[Kernel] Thread join failed, can only be called by root thread, current tid: {}",
cur_tid
);
return (usize::MAX, 0);
}
// 获取tid对应的线程
....
// 创建等待协程
current_thread.set_state(ThreadState::Waiting);
executor::spawn(WaitForThread::new(current_thread, waited_thread));
return (0, 0);
}
我们知道,一个进程中可能有多个正在运行的线程,一般来说,主线程负责回收所有的线程,当所有线程都退出后,主线程才能退出。
这里主线程等待其他线程退出,但是当主线程调用这个函数时,很可能发生子线程还在运行的情况,这就是一个典型的异步请求。
如何来实现一个异步的请求,这就是本章探讨的问题,我们将在后面几节中逐步介绍,这里首先可以看到我们将主线程设置为了Waiting
异步等待状态,并生成了一个WaitForThread
实例并加入到协程执行器(执行器)中,实际上这是一个协程,在下一节异步协程中就会详细说明。
完成协程创建后,这个函数就直接返回了,在调度一节我们知道,调度器不会调度Waiting
状态的线程,所以主线程暂时挂起了,不会被执行,但问题是什么时候它才会被唤醒呢?在后面几节我们就能找到答案。