Как работает кооперативная многозадачность?

Я прочитал этот фрагмент текста Википедии:

Поскольку совместная многозадачная система полагается на то, что каждый процесс регулярно отдает время другим процессам в системе, одна плохо спроектированная программа может потреблять все время ЦП для себя или вызывать зависание всей системы.

Из любопытства, как можно бросить это время? Это какой-то вызов ОС? Давайте подумаем о случаях без вытеснения, таких как волокна или четные операции ввода-вывода, которые выполняют совместную многозадачность. Как они отдают это время?

Возьмите этот пример NodeJS:

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

Для меня очевидно, что процесс ничего не делает, ожидая данных, но как V8 в этом случае отдает время другим процессам?

Давайте примем Linux/Windows в качестве нашей ОС.

Изменить: я узнал, как Google делает это с их V8.

На Windows они в основном спят ноль времени:

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

А в Linux они делают вызов ОС:

void Thread::YieldCPU() {
  sched_yield();
}

из sched.h,

3 ответа

Решение

Да, каждая программа участвует в решениях по планированию ОС, поэтому вам нужно вызвать определенный системный вызов, который сообщает ядру о необходимости возврата. Часто это называлось yield (). Если вы представляете, как трудно гарантировать, что определенная строка кода вызывается с регулярными, короткими интервалами или даже вообще, вы получите представление о том, почему совместная многозадачность является неоптимальным решением.

В вашем примере это сам движок javascript, который прерывается планировщиком ОС, если это превентивная ОС. Если это кооперативный, то нет, двигатель не выполняет никакой работы, как и любой другой процесс. В результате такие системы обычно не подходят для рабочих нагрузок в реальном времени (или даже серьезных).

Примером такой ОС является NetWare. В этой системе необходимо было вызывать определенную функцию (я думаю, что она называется ThreadSwitch или, возможно, ThreadSwitchWithDelay). И всегда было предположение, как часто это было необходимо. В каждом цикле, интенсивно использующем процессор, в продукте необходимо было периодически вызывать одну из этих функций.

Но в этой системе другие вызовы могут привести к запуску других потоков. В частности (и это актуально для вопроса), вызовы ввода / вывода привели к тому, что ОС получила возможность запускать другие потоки. По сути, любого системного вызова, который давал управление ОС, было достаточно для запуска других потоков (важными являются вызовы мьютекса / семафора).

Как правило, совместная многозадачность включает функции, сигнализирующие о том, что они теперь ждут, а не переходят в циклы вращения (где они обрабатывают во время ожидания), которые они приостанавливают.

В этом случае обработка ReadFile будет обрабатывать ожидание данных и соответствующую сигнализацию о том, что они приостановлены. Внутри вашего собственного кода, в чем бы он ни был написан, вы должны приостановить обработку, если вы ожидаете долгого процесса, а не вращения. Однако во многих случаях процессы приостановки обрабатываются автоматически, поскольку действия приостановки встроены. Опасность заключается в том, что если вы намеренно форсируете длительные вращения, вы повесите систему.

Альтернатива (из этой вики) - многозадачность с преимуществом, когда процесс вытесняется действием через определенное время, независимо от того, что он делает. Это означает, что что бы вы ни делали, оно не может работать вечно, потому что системный процесс его вытеснит. Однако это может быть менее эффективно, поскольку точки останова не определены.

Другие вопросы по тегам