4
  1. 有人可以解释一下协程和纤维是什么吗?与常规例程和多任务机制相比,它们解决了什么问题。
  2. 为什么 Linux 使用抢占式多任务而不是协作式多任务?
4

3 回答 3

7

协程、纤程和它们的同类是由编程语言运行时或库管理的类似线程的执行上下文,而不是由操作系统管理,操作系统认为它们是一体的。它们的用途有限;当真正的线程可用时,没有人在他们正常的头脑中使用这样的黑客。

说 Linux 使用抢占式多任务处理是一种简化。与早期的 Unix 一样,早期的 Linux 使用协作式多任务处理来运行内核代码。这意味着进程可以在执行用户空间时被抢占,但不能在执行内核代码时被抢占。在运行内核代码时,一个进程被取消调度以仅在它休眠时运行另一个进程,这是通过对某个休眠的阻塞函数进行一些自愿调用来实现的。这种方法极大地简化了操作系统内部,因为很多竞争条件都消失了。至少,如果只有一个处理器。运行内核代码的任务只需要担心中断,并且在不方便时可以暂时禁用这些中断。

随着 1990 年代中期在实验性 Linux 1.3 内核系列中引入对多处理器的支持,这种情况开始发生变化。非抢占式内核不能很好地支持 SMP,因为为了保证协作多任务,必须在内核周围放置一个大锁,一次只允许一个处理器进入。在 Linux 中,这被命名为 BKL(大内核锁)。

渐渐地,BKL 不再强制所有进入内核的入口,而是被更细粒度的 SMP 锁所取代。一旦你有多个处理器同时在内核空间中运行,就会出现一个有趣的情况:真正的并发正在进行,受到锁定机制的保护,但内核仍然是协作的,因为没有任务可以失去它正在运行的处理器除非它睡觉。

在这一点上,只允许抢占是有意义的。因此,它以选项的形式在内核中进行了工作,该选项CONFIG_PREEMPT已进行了多年试验,并且往往无法在所有体系结构中以及与 SMP 结合使用时始终如一地工作。

为什么希望内核可抢占只是因为它允许更好的实时处理:更短的事件响应时间。虽然抢占是有风险的,但大多数问题都是通过提高 SMP 的效率来解决的,这往往会降低采用抢占的门槛:即,这不是“为什么,为什么”的问题,而是“为什么不”的问题。

于 2013-05-27T05:01:08.757 回答
2

由于无法提供低延迟的 I/O 性能,协作式多任务处理程序受到了致命的削弱。

抢占式多任务程序使 I/O 等待线程准备好/运行、抢占其他正在运行的线程、驱动程序何时从中断返回的能力允许 GUI、浏览器等响应式运行以及视频/音乐播放器、BitTorrent、 YouTube 等实际上可以正常工作。

协作任务,如纤维和所谓的“绿色线程”无疑在特定领域有其用途,但它们在通用操作系统中几乎没有用处,这就是为什么 Linux、Windows(自 W95 以来,无论如何) ) 等等等等等等都使用抢占式多线程(或多处理,如果你喜欢的话)调度程序。

于 2013-05-27T04:59:51.423 回答
2

线程和纤程都是支持多个执行位置(代码路径)的抽象。

可以将其视为在这些位置之间共享某种资源 (CPU) 的方式。给定 CPU 的执行点就是执行点。

对于线程,何时将 CPU 分配给线程,何时拿走(即何时执行和不执行)的控制是外部的。外部实体(内核调度程序)决定线程何时获得 CPU 以及多长时间。时间通常是一个因素。内核在多个线程之间共享CPU,如果某个线程在一定时间后没有主动放弃CPU,内核就会将其拿走并以公平的方式让给另一个线程。内核可能使用各种调度算法来实现优先级、响应性和其他目标,但底线是 CPU 控制权掌握在内核手中。

使用协程(或纤程),执行轨迹可以让 CPU 保持多久,并且只是自愿放弃。此时内核可能会将 CPU 分配给另一个执行点。

请注意,“自愿”放弃 CPU 可以是显式的(通过使用某些系统调用),也可以是隐式的(当它内置到其他系统调用中,如信号量等待等时)。一般的经验法则是,如果系统调用可能涉及等待,则可能会在其中内置一个隐式调度点。

现在可能很明显,像 Linux 这样的通用内核并没有大量使用协程。这是因为协程在放弃 CPU 时具有太多的独立性。流氓光纤或行为不端的光纤可能会占用 CPU 太长时间,并使其他执行位置饿死。像 Linux 这样的执行环境喜欢更好地控制 CPU 在所有执行位置之间的调度方式。

于 2013-05-27T04:13:28.663 回答