2011-06-29 26 views
7

我读这个维基百科text片:合作多任务如何工作?

因为合作多任务系统定期依赖于每个进程放弃自己的时间到其他进程在系统上,一个设计不当的程序可以消耗所有的CPU时间本身或导致整个系统挂起。

出于好奇,如何放弃那个时间?这是某种操作系统调用?让我们考虑一下非抢先式的情况,比如光纤或者偶数IO,它们可以协同工作。他们如何放弃那个时间?

借此NodeJS例如:

var fs = require('fs'); 
fs.readFile('/path/to/file', function(err, data) {}); 

很明显,我认为该过程不执行任何操作,而它等待数据,但如何V8在这种情况下放弃了时间的其他进程?

让我们假设Linux/Windows作为我们的操作系统。

编辑:我发现谷歌是如何与他们的V8做到这一点。

Windows他们基本上睡零时间:

void Thread::YieldCPU() { 
    Sleep(0); 
} 

而且在Linux他们作出的操作系统调用:

void Thread::YieldCPU() { 
    sched_yield(); 
} 
sched.h

+0

内核是否决定哪个进程应该“放弃时间”? – Hannesh

+2

@Hannesh:这是抢先的多任务处理。 – sharptooth

回答

4

是的,每个程序都参与OS的调度决策,所以你必须调用一个特定的系统调用来告诉内核重新接管。通常这叫做yield()。如果您想象如何确保在规则的,短的时间间隔内甚至根本不会调用特定的代码是多么困难,您就会明白为什么协作式多任务是次优解决方案。

在你的例子中,它是JavaScript引擎本身被操作系统调度程序中断,如果它是一个抢占式操作系统。如果它是合作的,那么不是,引擎没有完成任何工作,也没有任何其他过程。因此,这些系统通常不适合实时(甚至是严重)的工作负载。

+0

+ 1,人们可以看看'Sleep()'Win32函数 - 而Win32使用抢先式多任务'Sleep()'就是这样做的。 – sharptooth

0

作为一般规则,合作多任务涉及的功能表明他们现在正在等待,而不是进入自旋循环(在等待中他们处理的过程中)他们暂停自己。

在这种情况下,ReadFile后面的处理将处理等待数据以及相关信号的可挂起状态。在您自己的代码中,无论它是否写入,如果您正在等待长时间运行的进程而不是旋转,则应该暂停处理。但是,在很多情况下,暂停过程会自动处理,因为暂停活动是内置的。如果您故意强制长时间旋转,那么会导致系统挂起。

替代方案(来自该wiki)是先发制人的多任务处理,在一定时间后,流程被强制停止,不管它在做什么。这意味着无论你做什么,它都不能永远运行,因为系统进程会强制它。但是,由于未定义中断点,效率可能会降低。

2

这种操作系统的一个例子是NetWare。在那个系统中,有必要调用一个特定的函数(我认为它被称为ThreadSwitch或ThreadSwitchWithDelay)。这总是一个猜测,它需要多长时间一次。在产品中的每个CPU密集型环路中,都需要定期调用其中一个功能。

但在该系统中,其他调用会导致允许其他线程运行。特别是(并且与这个问题密切相关)是I/O调用导致操作系统有机会运行其他线程。基本上任何控制操作系统的系统调用都足以让其他线程运行(互斥/信号调用是重要的)。