2013-12-08 2 views
2

С потоками пользовательского уровня существует N потоков пользовательского уровня, работающих поверх одного потока ядра. Это в отличие от pthreads, где только один пользовательский поток работает по потоку ядра.Как превентивное планирование реализовано для потоков пользовательского уровня в Linux?

N потоков пользовательского уровня предварительно запланировано для отдельного потока ядра. Но каковы детали того, как это делается.

Я слышал что-то, что предлагало, чтобы библиотека потоков собирала вещи так, чтобы сигнал посылался ядром, и это механизм для выполнения выполнения из отдельного потока пользовательского уровня в обработчик сигнала, который затем может выполнять превентивный планирования.

Но каковы детали того, как состояние, такое как регистры и структуры потоков, сохраняется и/или мутируется, чтобы все это работало? Может быть, очень простой поток пользовательского уровня, который полезен для изучения деталей?

ответ

2

Чтобы получить подробную информацию, используйте источник! Но это то, о чем я помню, когда читал ...

Существует два способа, по которым можно планировать потоки пользовательского уровня: добровольно и упреждающе.

  • добровольного планирования: потоки должны вызвать функцию периодически, чтобы передать использование CPU другому потоку. Эта функция называется yield() или schedule() или что-то в этом роде.
  • Предварительное планирование: библиотека принудительно удаляет процессор из одного потока и передает его другому. Обычно это делается с помощью сигналов таймера, таких как SIGALARM (подробнее см. man ualarm).

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

К сожалению, эти функции удалены из POSIX, поэтому другие UNIX могут не иметь их. Если это так, есть и другие трюки, которые можно сделать. Самым популярным был тот, кто вызывал sigaltstack(), чтобы настроить альтернативный стек для управления сигналами, а затем kill() сам, чтобы перейти в альтернативный стек, и longjmp() от сигнальной функции до фактического потока пользовательского режима, который вы хотите запустить. Умный, мм?

В качестве примечания стороны в потоках пользовательского режима Windows называются волокнами и также полностью поддерживаются (см. Документы от CreateFiber()).

Последнее средство использует ассемблер, который может работать почти везде, но он полностью зависит от конкретной системы. Шаги по созданию UMT будут следующими:

  • Выделить стек.
  • Выделить и инициализировать контекст UMT: структуру для хранения значений соответствующих регистров процессора.

и переключаться с одного УМТ к другому:

  • Сохранить текущий контекст.
  • Переключите стопку.
  • Восстановите следующий контекст в CPU и перейдите к следующей инструкции.

Эти шаги относительно просты в использовании ассемблером, но совершенно невозможны в обычном C без поддержки каких-либо трюков, упомянутых выше.

Смежные вопросы