erlang是如何用一个OS线程实现抢占式调度的?
How does erlang implements preemptive scheduling with one OS thread?
我想知道 erlang 的 VM 如何抢占 运行 代码和上下文堆栈。如何用 c 之类的语言来完成?
Erlang的所有代码都会编译成Erlang虚拟机的运行代码。 Erlang 的 VM 通过在 Erlang 的 VM 启动时创建的 OS 线程执行 Erlang 的操作代码。
Erlang 的代码 运行 在由 Erlang 的 VM 控制的虚拟 CPU 上。而 Erlang 的 VM 将 IO 视为虚拟 CPU 的中断。所以 Erlang 的 VM 像 OS 一样实现了一个机器和一个调度器。因为操作码和non-blockingIO,我们可以用C语言在Erlang的VM中实现抢占。
诀窍在于 Erlang 运行时可以控制 VM,因此它可以——完全在用户空间——跟踪它已经执行了多少 VM 指令(或者,更好的是,估计或表示实际物理这些指令所需的计算 - a.k.a。"reductions" 在 Erlang VM 的说法中)并且 - 如果该数字超过某个阈值 - 立即交换进程 pointers/structs/whatever 并恢复执行循环。
可以这样想(有点像伪 C,实际上可能是也可能不是 C,但我不知道,因为我不是 C 程序员,但你问过你怎么会在 C 中进行,所以我会尝试我最大胆的):
void proc_execute(Proc* proc)
{
/* I don't recall if Erlang's VM supports different
reduction limits for different processes, but if it
did, it'd be a rather intuitive way to define process
priorities, i.e. making sure higher-priority processes
get more reductions to spend */
int rds = proc->max_reductions;
for (; rds > 0; rds--) {
/* Different virtual instructions might execute different numbers of
physical instructions, so vm_execute_next_instruction will return
however many reductions are left after executing that virtual
instruction. */
rds = vm_execute_next_instruction(proc, rds);
if (proc->exited) break;
}
}
void vm_loop(Scheduler* sched)
{
Proc *proc;
for (;;) {
proc = sched_next_in_queue(sched);
/* we'll assume that the proc will be null if the
scheduler doesn't have any processes left in its
list */
if (!proc) break;
proc_execute(proc);
}
}
Proc* sched_next_in_queue(Scheduler* sched)
{
if (!sched->current_proc->exited) {
/* If the process hasn't exited yet, readd it to the
end of the queue so we can resume running it
later */
shift(sched->queue, sched->current_proc);
}
sched->current_proc = pop(sched->queue);
return sched->current_proc;
}
这显然非常简单(特别是 excluding/eliding 很多重要的东西,比如 VM 指令是如何实现的以及消息是如何传递的),但希望它说明了如何(如果我理解正确,至少) Erlang 的抢占式调度程序和进程模型在基础级别上工作。
我想知道 erlang 的 VM 如何抢占 运行 代码和上下文堆栈。如何用 c 之类的语言来完成?
Erlang的所有代码都会编译成Erlang虚拟机的运行代码。 Erlang 的 VM 通过在 Erlang 的 VM 启动时创建的 OS 线程执行 Erlang 的操作代码。
Erlang 的代码 运行 在由 Erlang 的 VM 控制的虚拟 CPU 上。而 Erlang 的 VM 将 IO 视为虚拟 CPU 的中断。所以 Erlang 的 VM 像 OS 一样实现了一个机器和一个调度器。因为操作码和non-blockingIO,我们可以用C语言在Erlang的VM中实现抢占。
诀窍在于 Erlang 运行时可以控制 VM,因此它可以——完全在用户空间——跟踪它已经执行了多少 VM 指令(或者,更好的是,估计或表示实际物理这些指令所需的计算 - a.k.a。"reductions" 在 Erlang VM 的说法中)并且 - 如果该数字超过某个阈值 - 立即交换进程 pointers/structs/whatever 并恢复执行循环。
可以这样想(有点像伪 C,实际上可能是也可能不是 C,但我不知道,因为我不是 C 程序员,但你问过你怎么会在 C 中进行,所以我会尝试我最大胆的):
void proc_execute(Proc* proc)
{
/* I don't recall if Erlang's VM supports different
reduction limits for different processes, but if it
did, it'd be a rather intuitive way to define process
priorities, i.e. making sure higher-priority processes
get more reductions to spend */
int rds = proc->max_reductions;
for (; rds > 0; rds--) {
/* Different virtual instructions might execute different numbers of
physical instructions, so vm_execute_next_instruction will return
however many reductions are left after executing that virtual
instruction. */
rds = vm_execute_next_instruction(proc, rds);
if (proc->exited) break;
}
}
void vm_loop(Scheduler* sched)
{
Proc *proc;
for (;;) {
proc = sched_next_in_queue(sched);
/* we'll assume that the proc will be null if the
scheduler doesn't have any processes left in its
list */
if (!proc) break;
proc_execute(proc);
}
}
Proc* sched_next_in_queue(Scheduler* sched)
{
if (!sched->current_proc->exited) {
/* If the process hasn't exited yet, readd it to the
end of the queue so we can resume running it
later */
shift(sched->queue, sched->current_proc);
}
sched->current_proc = pop(sched->queue);
return sched->current_proc;
}
这显然非常简单(特别是 excluding/eliding 很多重要的东西,比如 VM 指令是如何实现的以及消息是如何传递的),但希望它说明了如何(如果我理解正确,至少) Erlang 的抢占式调度程序和进程模型在基础级别上工作。