Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Гл.11 ОС буклет.doc
Скачиваний:
10
Добавлен:
11.11.2018
Размер:
357.38 Кб
Скачать

11.1.6. Поддержка многопроцессорности в Linux

Многопроцессорные архитектуры в Linux поддерживают, начиная из ядра версии 2.0 (1996 год). Поддержка многопроцессорности реализована в средствах синхронизации процессов и планировщике процессов.

Основы синхронизации в ядре Linux описаны в пункте 5.4.1. Первично реализация поддержки SMP основывалась на большой блокировке ядра. Современные версии ядра поддерживают подход с разделением кода на отдельные критические секции.

Многопроцессорное планирование

Ядро Linux версии 2.4 реализовывало стандартное планирование с делением времени. Полная реализация планирования, рассчитанная на использование в многопроцессорных архитектурах, в первый раз появилась в ядре версии 2.6 .

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

  • Реализованы системные вызовы, которые дают возможность задавать жесткое родство для процессов [79].

Для установления маски родства используют системный вызов sched_setaffinity():

#іinclude <sched.h>

long sched_setaffiirity(pid_t pid. unsigned int len.

unsigned long *user_mask_ptr):

где: pid— идентификатор процесса (0 — текущий процесс);

len — длина маски;

user_mask_ptr — указатель на переменную, которая содержит маску.

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

unsigned long mask = 7; // привязать процесс к процессорам 0. 1 и 2

sched_setaffinity(), sizeof(mask), &mask);

Реализация жесткого родства в ядре

Маску процесса хранят в его дескрипторе task_struct как поле cpus_allowed. В случае любой попытки миграции процесса на новый процессор ядро проверяет, установлен в этом поле бит, который отвечает этому процессору. Если бит не установлен, миграция процесса не происходит. Кроме того, если в результате изменения маски выяснится, что процесс выполняется на недопустимом процессоре, он немедленно мигрирует на один из указанных в новом значении маски.

Поддержка NUMA-систем

Поддержка архитектуры NUMA была впервые реализована в ядре версии 2.6. Основой такой поддержки является внутреннее отображение топологии узлов, для работы с которыми назначен специальный программный интерфейс топологии (Topology API). Информацию о топологии узлов используют во время планирования процессов. Основной целью планирования является повышение вероятности использования локальной памяти.

11.1.7. Поддержка многопроцессорной в Windows xp

При условиях многопроцессорной системы планировщик Windows XP определяет порядок выполнения потоков и процессоры, на которых они должны выполняться. При этом по умалчанию поддерживают мягкое родство. Кроме того, аналогично к Linux в системе может быть задано жесткое родство на основе маски родства, а среди процессоров, заданных в маске родства потока, дополнительно выбирают идеальный процессор (ideal processor). Планировщик планирует поток для выполнения на идеальном процессоре, если он является доступным в этот момент.

Маска родства потока, номер идеального процессора и номер процессора, на котором поток выполнялся последний раз, содержатся в управляющем блоке потока (KTHREAD), маска родства процесса — в блоке KPR0CESS. Во время создания потока его маску родства будут инициализировать значением маски родства процесса.

В случае постановки потока на выполнение происходят такие действия.

  1. Процессором, на котором будет выполняться поток, планировщик пытается сделать идеальный процессор.

  2. Если идеальный процессор не доступен, выбирают процессор, на котором поток выполнялся в последний раз.

  3. Если и этот процессор занят, выбирают другой свободный процессор или процессор, на котором выполняется поток с низшим приоритетом.

Задання жесткого родства и идеального процессора

Жесткое родство может быть задано (маска родства изменена из программы) с помощью функций SetProcessAffinityMask() (для процесса) или SetThreadAffinityMask() (для отдельного потока).

DWORD mask_proc = 2; // второй процессор (маска 000...0010) SetProcessAffinityMask(GetCurrentProcess(). &mask_proc)

Для определения текущего значения маски родства процесса используют функцию GetProcessAffinityMask().

DWORD mask_proc. mask_sys;

// в маске mask_sys отключены биты для всех доступных процессоров

GetProcessAff1nityMask(GetCurrentProcess(), &mask_proc, &mask_sys);

printf("маска процесса: %081х. системная маска: %081х\n",

mask_proc. mask_sys):

Идеальный процессор выбирают случайно во время создания потока. Чтобы изменить его из применения, нужно использовать функцию SetThreadIdeal Processor().

SetThreadIdealProcessor(GetCurrentThread(), 1); // второй процессор

Поддержка NUMA-систем

Windows XP, как и Linux, поддерживает внутреннее отображение топологии узлов и использует его во время планирования потоков. Win32 АРI содержит ряд функций, которые дают возможность получить информацию о текущей топологии (например, функция GetNumaProcessorNode() возвращает номер узла для заданного процессора). Эту информацию можно применить для оптимизации использования локальной памяти, например путем задання маски родства, которое включает все процессоры одного узла.