有时,每当我在Linux中编写程序并因某种错误而崩溃时,它将成为一个不间断的过程并继续运行,直到我重新启动计算机(即使我退出).我的问题是:
用你自己的话来解释,什么是抢占以及它对(linux)内核意味着什么?
拥有可抢占内核有哪些优缺点?
我最近正在阅读Linux内核开发,我有一些与禁用抢占相关的问题.
在第7章的"中断控制"部分,它说:
此外,禁用中断还会禁用内核抢占.
我还从书中读到,在以下情况下可能会发生内核抢占:
当中断处理程序退出时,返回内核空间之前.
当内核代码再次成为可抢占状态时.
如果内核中的任务显式调用schedule()
如果内核中的任务阻塞(导致调用schedule())
但我无法将禁用中断与这些情况联系起来.
据我所知,自旋锁将使用preempt_disable()函数禁用抢占.
帖子究竟什么是"自旋锁"? 说:
在单核心机器上,自旋锁只是"禁用中断"或"引发IRQL",这完全阻止了线程调度.
preempt_disable()是否通过禁用中断来禁用抢占?
想知道如何调用调度程序以便它可以切换任务.就像在其抢占式调度或循环调度一样 - 调度程序应该进入图像来进行任何类型的任务切换.假设低优先级任务具有无限循环 - 调度程序何时进行干预并切换到更高优先级的任务?
查询是:1.谁调用调度程序?[在VxWorks中] 2.如果定期调用它 - 该机制是如何实现的?
提前致谢.
--Ashwin
当内核空间中spin_lock
的进程持有a时,由于以下任何一种情况,该进程无法被抢占:
但是,如果处理器阻塞,休眠或显式调用,则该过程可以产生处理器schedule()
.我的理解是否正确?
当内核空间mutex_lock
中的进程持有a时,由于上面列出的条件为1,2和3,该进程可以被抢占.
我很难理解先发制人的一件事.引用维基百科:
在计算中,抢占(更正确地抢占)是暂时中断由计算机系统执行的任务的行为,而不需要其合作,并且意图在稍后的时间恢复任务.这种变化称为上下文切换.它通常由特权任务或称为抢占式调度程序的系统的一部分执行,该系统具有抢占,中断和稍后恢复系统中其他任务的能力.
所以,基本上,他们说调度程序可以中断当前正在运行的任务.这怎么可能呢?CPU正在运行此任务的代码,而不是调度程序的代码.那么调度程序如何做任何事情呢?
我的猜测是必须有某种硬件定时器,在经过一段时间后会物理地中断CPU并将控制权交还给调度程序.它是否正确?有没有我可以更详细地阅读的文件?
任何答案都将受到高度赞赏.
为了给你完整的上下文,我的讨论开始于观察我在基于ARM皮层A8的SoC上运行SMP linux(3.0.1-rt11),这是一个单处理器.我很想知道通过禁用SMP支持是否会有任何性能优势.如果是,它会对我的驱动程序和中断处理程序产生什么影响.
我做了一些阅读并遇到了两个相关的主题:自旋锁和内核抢占.我没有做更多的谷歌搜索和阅读,但这次我得到的是一些陈旧和矛盾的答案.所以我想让我试试stackoverflow.
我的怀疑/问题的起源是来自Linux设备驱动程序第3版第5章的这一段:
就其本质而言,自旋锁旨在用于多处理器系统,尽管就并发性而言,运行抢占式内核的单处理器工作站的行为类似于SMP.如果一个非抢占式单处理器系统进入锁定旋转,它将永远旋转; 没有其他线程能够获得CPU来释放锁.出于这个原因,在没有启用抢占的单处理器系统上的自旋锁操作被优化为什么也不做,除了那些改变IRQ屏蔽状态的操作.由于抢占,即使您从未期望您的代码在SMP系统上运行,您仍然需要实现正确的锁定.
我的疑惑/问题是:
a)默认情况下,Linux内核是否在内核空间中抢先一步?如果是,此抢占是否仅限于进程或中断处理程序也可以被抢占?
b)Linux内核(在ARM上)是否支持嵌套中断?如果是,每个中断处理程序(上半部分)是否都有自己的堆栈,或者它们共享相同的4k/8k内核模式堆栈?
c)如果我禁用SMP(Config_SMP)并且抢占(Config_preempt)将在我的驱动程序和中断处理程序中旋转锁定有意义吗?
d)内核如何处理在执行上半部分时引发的中断,即它们是被禁用还是被屏蔽?
经过一些谷歌搜索我发现了这个:
对于没有CONFIG_SMP编译的内核,如果没有CONFIG_PREEMPT,则根本不存在自旋锁.这是一个很好的设计决策:当没有其他人可以同时运行时,没有理由拥有锁.
如果在没有CONFIG_SMP的情况下编译内核,但设置了CONFIG_PREEMPT,那么自旋锁只会禁用抢占,这足以防止任何比赛.在大多数情况下,我们可以认为抢占等同于SMP,而不是单独担心它.
但是源上没有内核版本或日期.任何人都可以确认它是否仍然适用于最新的Linux内核?
维基百科说:
在计算中,抢占是暂时中断计算机系统正在执行的任务的行为,不需要它的合作,并打算在以后恢复任务。
其他消息来源说:
[...] 抢占意味着从一个进程中强行夺走处理器并将其分配给另一个进程。[操作系统 (Self Edition 1.1), Sibsankar Haldar ]
当程序在执行过程中出现中断并且调度程序选择一些其他程序执行时,就会发生程序的抢占。[操作系统:基于概念的方法,2E,DM Dhamdhere ]
所以,我的理解是,如果进程被中断(通过硬件中断,即 I/O 中断或定时器中断),并且在处理中断后调用的调度程序选择另一个进程运行(根据CPU调度算法)。如果调度器选择了被中断的进程,我们就没有进程抢占(中断不一定会导致抢占)。
但我发现许多其他来源以下列方式定义抢占:
抢占是从程序中强制释放 CPU。[操作系统:基于概念的方法,2E,DM Dhamdhere ]
您可以看到同一本书报告了两种不同的抢占定义。在后者中没有提到必须将 CPU 分配给另一个进程。根据这个定义,抢占只是“中断”的另一个名称。当硬件中断出现时,进程被中断(它从“运行”状态切换到“就绪”状态)或被抢占。
所以我的问题是:这两个定义中哪一个是正确的?我很困惑。
我想知道是否有可能在Linux上的用户空间中的单个进程中实现本机代码的抢占式多任务处理.(也就是说,从外部暂停一些正在运行的本机代码,保存上下文,在不同的上下文中交换,以及恢复执行,所有这些都由用户空间协调,但使用可能进入内核的调用.)我以为这可以使用信号来完成处理器SIGALRM
和*context()
家庭,但事实证明,整个*context()
家庭是异步信号不安全的,所以不能保证方法的工作.我确实发现了一个实现这个想法的要点,所以显然它确实在Linux上运行,至少有时候,即使POSIX也不需要工作.gist将其作为信号处理程序安装SIGALRM
,进行多次*context()
调用:
void
timer_interrupt(int j, siginfo_t *si, void *old_context)
{
/* Create new scheduler context */
getcontext(&signal_context);
signal_context.uc_stack.ss_sp = signal_stack;
signal_context.uc_stack.ss_size = STACKSIZE;
signal_context.uc_stack.ss_flags = 0;
sigemptyset(&signal_context.uc_sigmask);
makecontext(&signal_context, scheduler, 1);
/* save running thread, jump to scheduler */
swapcontext(cur_context,&signal_context);
}
Run Code Online (Sandbox Code Playgroud)
Linux是否提供使这种方法正确的保证?有没有办法使这个正确吗?是否有完全不同的方法正确地做到这一点?
(通过"在用户空间中实现"我并不是说我们永远不会进入内核.我的意思是与内核实现的抢先式多任务进行对比.)
在 Kubernetes 中,我们可以将 pod 的优先级设置为Guaranteed
,Burstable
或Best-Effort
基于请求和限制。在 Kubernetes 中分配优先级的另一种方法是定义一个priorityClass
对象并将 a 分配priorityClassName
给 pod。这些方法有何不同?何时我们必须选择一种方法而不是另一种方法?根据https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#interactions-of-pod-priority-and-qos:
\n\n\nScheduler\xe2\x80\x99s 抢占逻辑在选择抢占目标时不考虑 QoS。抢占会考虑 Pod 优先级并尝试选择一组优先级最低的目标。
\n
因此,如果 Kubernetes 必须在具有Guaranteed
QoS 且“priorityClass”值低于Burstable
pod 的 pod 之间进行选择,是否会将Guaranteed
pod 置于抢占状态?
preemption ×10
linux ×4
linux-kernel ×3
interrupt ×2
scheduling ×2
spinlock ×2
c ×1
cpu ×1
kernel ×1
kubernetes ×1
locking ×1
multitasking ×1
qos ×1
scheduler ×1
signals ×1
smp ×1
vxworks ×1
x86 ×1