Рассмотрите многопользовательскую ОС с планировщиком по приоритетам, где интерактивные процессы получают высокий приоритет и фоновые низкий: опишите сценарии взаимной блокировки и голодания (starvation), предложите модификации планировщика (с примерами эвристик или псевдокода), которые сохраняют отзывчивость интерактивных задач и ограничивают время ожидания фоновых задач
Сценарии (кратко, с пояснениями) - Приоритетная инверсия (взаимная блокировка по ресурсу): интерактивный процесс III (высокий приоритет) ждёт мьютекса, который захватил фоновый процесс BBB (низкий приоритет). Между ними может вставать поток средней приоритета MMM, который занимает CPU, не давая BBB освободить мьютекс — результат: III блокирован пока не завершит MMM. Это классическая инверсия приоритетов, фактически блокировка III из‑за того, что держатель ресурса не получает CPU. - Классический дедлок по циклу захвата ресурсов: два процесса P1P_1P1 и P2P_2P2 держат разные ресурсы и ждут чужих; если P1P_1P1 — интерактивный, а P2P_2P2 — фоновый, система может «заморозить» и отзывчивость пострадает, если фоновый не сможет быть запущен для освобождения ресурса. - Голодание (starvation) фоновых задач: при непрерывном потоке интерактивных задач фоновые никогда не получают CPU. Формально: если приход интерактивных задач такой, что общий занятый интерактивный CPU доли →1\to 1→1, то время ожидания фоновой задачи twait→∞t_{wait}\to\inftytwait→∞. - Непримитивное голодание: длинные неконкурентные секции (non‑preemptible) у интерактивных задач — даже редкие, но долгие такие секции блокируют фоновые на большие интервалы. Предлагаемые модификации планировщика (цель: сохранить отзывчивость интерактивных и ограничить ожидание фоновых) 1) Приоритетное «донорство» при блокировках (priority inheritance) - Идея: если задача AAA ждёт лок на LLL, и держатель HHH имеет меньший приоритет, временно повысить приоритет HHH до приоритета AAA до освобождения. - Псевдокод (упрощённо): acquire_lock(L, requester): if L.holder == NULL: L.holder = requester else: if L.holder.priority < requester.priority: donate_priority(L.holder, requester.priority) block requester on L release_lock(L): L.holder = next_waiter restore_priority(previous) // откат донорства - Эффект: устраняет приоритетную инверсию без значительного ухудшения отзывчивости. 2) Старение приоритета (aging) с ограничением повышений - Формула эффективного приоритета: peff(t)=min(pmax, p0+α⋅twait)
p_{eff}(t)=\min(p_{max},\,p_0+\alpha\cdot t_{wait}) peff(t)=min(pmax,p0+α⋅twait)
где p0p_0p0 — базовый приоритет, twaitt_{wait}twait — время в очереди, α\alphaα — скорость старения, pmaxp_{max}pmax — потолок. - Практический приём: сделать pmaxp_{max}pmax чуть ниже порога для интерактивных пиков, чтобы не полностью лишить интерактивности, и комбинировать с гарантией CPU (см. пункт 3). - Псевдокод: update_priority(task): task.p_eff = min(p_max, task.p0 + alpha * task.wait_seconds) 3) Гарантированное окно/доля CPU для фоновых (reservations / periodic window) - Идея: в каждом периоде PPP система гарантирует фоновым задачам не менее доли fff CPU (0<f<10<f<10<f<1). - Гарантия даёт верхнюю границу на задержку: задача с потребностью CPU CCC завершится не позднее Cf\frac{C}{f}fC секунд. - Псевдокод (упрощённо): window_start(): bg_used = 0 scheduler_select(): if bg_used < f * P and exists runnable_background: pick background task (round‑robin) else: pick highest p_eff runnable task on_context_switch(to_task, duration): if to_task.is_background: bg_used += duration - Пример параметров: P=P=P=111 s, f=f=f=0.10.10.1 (10% CPU для фоновых) — фоновые получат связный гарантированный минимум при малом ущербе отзывчивости. 4) MLFQ с периодическим «подъёмом» (MLFQ + boost) - Несколько уровней очередей: интерактивная верхняя, фоновая нижняя. Каждые TboostT_{boost}Tboost все задачи повышаются в приоритете (или очереди сбрасываются), чтобы предотвратить бесконечное голодание. - Параметры: интервал буста TboostT_{boost}Tboost выбирается так, чтобы интерактивность не страдала (TboostT_{boost}Tboost порядка сотен мс–секунд). - Псевдокод: every T_boost: for task in all_tasks: promote(task) // или сбросить к начальному уровню 5) Ограничение времени выполнения интерактивной задачи (time quantum / soft throttling) - Если интерактивная задача занимает CPU больше порога TlongT_{long}Tlong, на время снизить её эффективный приоритет (или снять интерактивный флаг), чтобы другие могли выполниться. - Параметр: TlongT_{long}Tlong = например 100100100–500500500 ms. 6) Комбинированная стратегия (рекомендуемая) - Приоритетное донорство для блокировок (убирает инверсии). - Aging с формулой peff=min(pmax,p0+αtwait)p_{eff}=\min(p_{max},p_0+\alpha t_{wait})peff=min(pmax,p0+αtwait). - Гарантированная доля fff в периоде PPP для фоновых (даёт жёсткие пределы ожидания: время выполнения C≤C/fC\le C/fC≤C/f). - MLFQ boost как страховка от долгого голодания. - Ограничение длительности квантов интерактива для подавления CPU‑хогов. Пример числовых настроек (пример, все числа в KaTeX) - диапазон приоритетов p∈[0,100]p\in[0,100]p∈[0,100], интерактивные стартуют p0=90p_0=90p0=90, фоновые p0=20p_0=20p0=20; - старение α=5\alpha=5α=5 единиц/с, потолок pmax=80p_{max}=80pmax=80; - гарантированная доля фоновых f=0.1f=0.1f=0.1 в периоде P=1P=1P=1 s; - boost интервал Tboost=200T_{boost}=200Tboost=200 ms; - порог долга интеракта Tlong=200T_{long}=200Tlong=200 ms. Короткая оценка гарантий - Сочетание aging+reservation даёт «мягкие» и «жёсткие» гарантии: старение уменьшает ожидание эмпирически, а резерв fff даёт формальную границу на задержку фоновых задач: задача с CPU‑требованием CCC завершится за не более Cf\frac{C}{f}fC реального времени при постоянной конкуренции. Практические замечания - Параметры нужно подбирать по нагрузке; слишком агрессивное повышение приоритета снижает отзывчивость. - Priority inheritance должен быть применён на уровне синхронизаторов (mutex, IO locks). - Для мульти‑юзерных систем стоит применять доли/квоты по пользователям, чтобы один пользователь‑интерактивщик не убивал всех фоновых задач других. (Резюме: используйте priority inheritance для удаления инверсий, aging + потолок для плавного снятия голодания, плюс небольшую жёсткую гарантию CPU fff в окне PPP и периодический boost/ограничения квантов для страховки — это сохраняет отзывчивость интерактивных задач и ограничивает ожидание фоновых.)
- Приоритетная инверсия (взаимная блокировка по ресурсу): интерактивный процесс III (высокий приоритет) ждёт мьютекса, который захватил фоновый процесс BBB (низкий приоритет). Между ними может вставать поток средней приоритета MMM, который занимает CPU, не давая BBB освободить мьютекс — результат: III блокирован пока не завершит MMM. Это классическая инверсия приоритетов, фактически блокировка III из‑за того, что держатель ресурса не получает CPU.
- Классический дедлок по циклу захвата ресурсов: два процесса P1P_1P1 и P2P_2P2 держат разные ресурсы и ждут чужих; если P1P_1P1 — интерактивный, а P2P_2P2 — фоновый, система может «заморозить» и отзывчивость пострадает, если фоновый не сможет быть запущен для освобождения ресурса.
- Голодание (starvation) фоновых задач: при непрерывном потоке интерактивных задач фоновые никогда не получают CPU. Формально: если приход интерактивных задач такой, что общий занятый интерактивный CPU доли →1\to 1→1, то время ожидания фоновой задачи twait→∞t_{wait}\to\inftytwait →∞.
- Непримитивное голодание: длинные неконкурентные секции (non‑preemptible) у интерактивных задач — даже редкие, но долгие такие секции блокируют фоновые на большие интервалы.
Предлагаемые модификации планировщика (цель: сохранить отзывчивость интерактивных и ограничить ожидание фоновых)
1) Приоритетное «донорство» при блокировках (priority inheritance)
- Идея: если задача AAA ждёт лок на LLL, и держатель HHH имеет меньший приоритет, временно повысить приоритет HHH до приоритета AAA до освобождения.
- Псевдокод (упрощённо):
acquire_lock(L, requester):
if L.holder == NULL:
L.holder = requester
else:
if L.holder.priority < requester.priority:
donate_priority(L.holder, requester.priority)
block requester on L
release_lock(L):
L.holder = next_waiter
restore_priority(previous) // откат донорства
- Эффект: устраняет приоритетную инверсию без значительного ухудшения отзывчивости.
2) Старение приоритета (aging) с ограничением повышений
- Формула эффективного приоритета:
peff(t)=min(pmax, p0+α⋅twait) p_{eff}(t)=\min(p_{max},\,p_0+\alpha\cdot t_{wait})
peff (t)=min(pmax ,p0 +α⋅twait ) где p0p_0p0 — базовый приоритет, twaitt_{wait}twait — время в очереди, α\alphaα — скорость старения, pmaxp_{max}pmax — потолок.
- Практический приём: сделать pmaxp_{max}pmax чуть ниже порога для интерактивных пиков, чтобы не полностью лишить интерактивности, и комбинировать с гарантией CPU (см. пункт 3).
- Псевдокод:
update_priority(task):
task.p_eff = min(p_max, task.p0 + alpha * task.wait_seconds)
3) Гарантированное окно/доля CPU для фоновых (reservations / periodic window)
- Идея: в каждом периоде PPP система гарантирует фоновым задачам не менее доли fff CPU (0<f<10<f<10<f<1).
- Гарантия даёт верхнюю границу на задержку: задача с потребностью CPU CCC завершится не позднее Cf\frac{C}{f}fC секунд.
- Псевдокод (упрощённо):
window_start():
bg_used = 0
scheduler_select():
if bg_used < f * P and exists runnable_background:
pick background task (round‑robin)
else:
pick highest p_eff runnable task
on_context_switch(to_task, duration):
if to_task.is_background:
bg_used += duration
- Пример параметров: P=P=P= 111 s, f=f=f= 0.10.10.1 (10% CPU для фоновых) — фоновые получат связный гарантированный минимум при малом ущербе отзывчивости.
4) MLFQ с периодическим «подъёмом» (MLFQ + boost)
- Несколько уровней очередей: интерактивная верхняя, фоновая нижняя. Каждые TboostT_{boost}Tboost все задачи повышаются в приоритете (или очереди сбрасываются), чтобы предотвратить бесконечное голодание.
- Параметры: интервал буста TboostT_{boost}Tboost выбирается так, чтобы интерактивность не страдала (TboostT_{boost}Tboost порядка сотен мс–секунд).
- Псевдокод:
every T_boost:
for task in all_tasks:
promote(task) // или сбросить к начальному уровню
5) Ограничение времени выполнения интерактивной задачи (time quantum / soft throttling)
- Если интерактивная задача занимает CPU больше порога TlongT_{long}Tlong , на время снизить её эффективный приоритет (или снять интерактивный флаг), чтобы другие могли выполниться.
- Параметр: TlongT_{long}Tlong = например 100100100–500500500 ms.
6) Комбинированная стратегия (рекомендуемая)
- Приоритетное донорство для блокировок (убирает инверсии).
- Aging с формулой peff=min(pmax,p0+αtwait)p_{eff}=\min(p_{max},p_0+\alpha t_{wait})peff =min(pmax ,p0 +αtwait ).
- Гарантированная доля fff в периоде PPP для фоновых (даёт жёсткие пределы ожидания: время выполнения C≤C/fC\le C/fC≤C/f).
- MLFQ boost как страховка от долгого голодания.
- Ограничение длительности квантов интерактива для подавления CPU‑хогов.
Пример числовых настроек (пример, все числа в KaTeX)
- диапазон приоритетов p∈[0,100]p\in[0,100]p∈[0,100], интерактивные стартуют p0=90p_0=90p0 =90, фоновые p0=20p_0=20p0 =20;
- старение α=5\alpha=5α=5 единиц/с, потолок pmax=80p_{max}=80pmax =80;
- гарантированная доля фоновых f=0.1f=0.1f=0.1 в периоде P=1P=1P=1 s;
- boost интервал Tboost=200T_{boost}=200Tboost =200 ms;
- порог долга интеракта Tlong=200T_{long}=200Tlong =200 ms.
Короткая оценка гарантий
- Сочетание aging+reservation даёт «мягкие» и «жёсткие» гарантии: старение уменьшает ожидание эмпирически, а резерв fff даёт формальную границу на задержку фоновых задач: задача с CPU‑требованием CCC завершится за не более Cf\frac{C}{f}fC реального времени при постоянной конкуренции.
Практические замечания
- Параметры нужно подбирать по нагрузке; слишком агрессивное повышение приоритета снижает отзывчивость.
- Priority inheritance должен быть применён на уровне синхронизаторов (mutex, IO locks).
- Для мульти‑юзерных систем стоит применять доли/квоты по пользователям, чтобы один пользователь‑интерактивщик не убивал всех фоновых задач других.
(Резюме: используйте priority inheritance для удаления инверсий, aging + потолок для плавного снятия голодания, плюс небольшую жёсткую гарантию CPU fff в окне PPP и периодический boost/ограничения квантов для страховки — это сохраняет отзывчивость интерактивных задач и ограничивает ожидание фоновых.)