我目前正在攻读操作系统的本科课程.我对调度程序和调度程序在进程调度中的功能感到有些困惑.基于我所学到的,中期调度程序选择交换和输入的过程,并且一旦选择了过程,实际的交换操作由Dispatcher通过上下文切换执行.此外,短期调度程序负责根据所遵循的调度算法调度进程并为它们分配CPU时间.如果我错了,请纠正我.我对中期调度程序与调度程序的功能以及交换和上下文切换之间的差异感到困惑.
我一直在努力在JavaScript中实现一个非常复杂的系统,需要模拟多线程进程.在真正的多线程进程(例如内核线程)中,可以通过上下文切换在线程之间切换.这是有效的,因为您可以存储当前进程的程序计数器并注册到临时结构,还原程序计数器并注册其他进程,然后在上一个进程中从中断处继续.
我很好奇是否可以在JavaScript中使用类似的东西.我目前不知道这样做,所以一直在使用协作式多任务设计系统.特别是,我想在多线程模拟器中运行的任何"函数"被分成一个函数数组.为了执行"函数",我遍历函数数组,按顺序执行每个函数,同时保持接下来执行哪个函数的"程序计数器".这允许我通过调用数组中的一个函数来模拟上下文切换,等待函数返回,然后切换到需要执行的其他一些函数数组.
我目前的方法有效,但在这个系统中编写代码很困难.每个函数必须具体指明它何时可以被中断,并且因为数组中的函数都是分开的,所以在函数的不同部分之间传递数据的逻辑是复杂的.我希望能够更接近先发制人的多任务工作.
我的问题是:是否可以以可以被外部源挂起和恢复的方式运行任意JavaScript函数?
我刚开始研究系统调用.我想知道在进行系统调用时导致开销的原因.
例如,如果我们考虑getpid(),当对getpid()进行系统调用时,我的猜测是如果控件当前在子进程中,则必须进行上下文切换以进入父进程以获取pid .这会导致开销吗?
此外,当调用getpid()时,将在用户空间边界上进行一些元数据传输并进入和退出内核.那么用户空间和内核之间的常量切换是否也会导致一些开销?
我正在编写一个使用第三方库来执行繁重计算的应用程序.
该库在内部实现并行性并产生给定数量的线程.我想运行这个库的几个(动态计数)实例,因此最终过度订阅了cpu.
有没有什么方法可以增加进程中所有线程的"时间量",以便例如所有具有正常优先级的线程很少上下文切换(yield),除非它们通过例如信号量明确地产生?
这样我就可以避免过度订阅cpu的大部分性能开销.请注意,在这种情况下,我不在乎线程是否缺乏几秒钟.
编辑:
一种复杂的方法是手动执行线程调度.
这种方法有什么主要缺点吗?不确定恢复/暂停线程的开销是多少?
当我遇到这个时,我只是在阅读我的操作系统中的linux如何工作.
[...]内核被创建为单个单一的二进制文件.主要原因是提高性能.由于所有内核代码和数据结构都保存在单个地址空间中,因此当进程调用操作系统函数或传递硬件中断时,不需要上下文切换.
这听起来对我来说非常了不起,当然它必须存储进程的上下文才能运行到内核模式来处理中断..但好吧,我现在就买它.在描述进程的调度上下文时,有几页,它说:
进程执行时发生的系统调用和中断都将使用此堆栈.
"这个堆栈"是内核存储进程寄存器等的地方.
这不是第一次引用的直接矛盾吗?我不知道以某种方式解释它吗?
我有一个多线程应用程序,在某段代码中我用a Stopwatch来衡量一个操作的时间:
MatchCollection matches = regex.Matches(text); //lazy evaluation
Int32 matchCount;
//inside this bracket program should not context switch
{
//start timer
MyStopwatch matchDuration = MyStopwatch.StartNew();
//actually evaluate regex
matchCount = matches.Count;
//adds the time regex took to a list
durations.AddDuration(matchDuration.Stop());
}
Run Code Online (Sandbox Code Playgroud)
现在,问题是如果程序在秒表启动时将控制切换到另一个其他线程,那么定时持续时间将是错误的.在上下文切换回此部分之前,另一个线程可以完成任何工作量.
请注意,我不是在询问锁定,这些都是局部变量,因此不需要这样做.我只想让定时部分连续执行.
编辑:另一个解决方案可能是减去上下文切换时间,以获得在定时部分完成工作的实际时间.不知道是否可能.
如果有 10 个进程 P1,P2...P10,并由调度程序使用循环策略调度来访问 CPU。现在当进程P1正在使用CPU并且当前时间片已过期时,P1需要被抢占,P2需要被调度。但是既然P1正在使用CPU,那么谁抢占P1并调度P2呢?我们可能 Scheduler 会这样做,但是当 CPU 被 P1 占用时,调度程序如何运行呢?
在裸机系统(嵌入式微控制器,没有MMU,没有寻呼)什么更昂贵?完整的上下文切换(寄存器保存和恢复)或函数调用(激活记录分配)?
我知道这很大程度上取决于调用约定和硬件功能,但我将如何评估它呢?
编辑:
为了提供更多的上下文,我试图模拟两个调度方案.第一个是先发制人的调度程序,在任务之间切换上下文.第二个是函数指针运行队列,其中任务是状态机,分为几个可以进行的函数调用(其中,在IO事件驱动的基础上进行排队).
在大多数情况下,我可以收集关于我的任务需要多长时间(IO和CPU时间)的良好数据,但我需要一些帮助来计算在我的模型中添加常量的额外开销成本.
architecture operating-system function overhead context-switch
我正在为 Cortex M4F 编写线程代码。一切正常,我现在正在研究通过惰性堆栈使 FPU 上下文切换更有效。
我读过 ARM 的AN298,并实现了基于禁用 FPU 和处理UsageFault 的替代方法,但较低的 ( S0-S15) 寄存器没有被硬件正确保存/恢复。我认为问题出在图11:
据此,当PendSV运行时FPCAR应该指向任务A的堆栈中保留的空间。但正如我所见,由于CONTROL.FPCA在任务 C 中处于高位,FPCAR因此在进入 PendSV 时将更新为指向任务 C 的堆栈。如果是这样,S0-S15并且FPSCR将被保存到任务C的堆栈而不是任务A的堆栈中,这当然是不正确的。
我在这里遗漏了什么,还是应用程序注释错误?
附带说明一下,我检查了一些开源 RTOS。FreeRTOS 和 mbed RTOS 始终S16-S31在上下文切换期间进行堆栈,从而导致自动S0-S15堆栈,即它们仅使用惰性堆栈来减少中断延迟,但对任务进行完整的状态保存(如应用笔记中概述的第一种方法)。M4F 的 TNKernel 端口使用UsageFault 方法,但S0-S31通过软件完全保存/恢复,有效地绕过任何问题FPCAR(以 48 次加载/存储而不是 32 次为代价,16 个硬件加载/存储在恢复时被覆盖)。似乎没有人在只保留S16-S31.
(顺便说一句,这也发布在ARM Community 上,但那里似乎有很多问题没有答案。如果我在那里得到答案,我也会在这里复制它)
在我的操作系统课程中,考试需要了解的问题之一是“为什么上下文切换成本高昂?” 贵是什么意思,贵是什么意思?就执行任务所需的时间而言?
context-switch ×10
process ×4
scheduler ×2
architecture ×1
arm ×1
c ×1
c# ×1
c++ ×1
cortex-m ×1
cpu ×1
fpu ×1
function ×1
javascript ×1
linux-kernel ×1
os161 ×1
overhead ×1
performance ×1
system-calls ×1
timing ×1
winapi ×1