Параллельное выполнение задач означает, что несколько задач выполняются одновременно. Для этого используются параллельные вычислительные системы, такие как многоядерные процессоры, процессоры с многочиповой архитектурой и многоядерные платформы. Кроме того, для параллельного выполнения задач можно использовать параллельные программные библиотеки и фреймворки, например OpenMP или MPI.
Начиная с исторической перспективы, в старые времена процессоры имели только один поток. Чтобы достичь многозадачности, были разработаны операционные системы с вытеснением задач. В этой системе задачи работают по очереди, приоритетно. Задача выполняется до завершения, а затем запускается следующая задача в очереди. Однако проблема возникала с ожиданием операций ввода-вывода, которые могли занимать длительное время. Для этого были разработаны прерывания, которые сигнализировали об окончании операции ввода-вывода. Поэтому были созданы операционные системы с вытеснением задач по прерыванию. Таким образом, прерывания от внешних устройств и таймера помогали переключаться между задачами. Современные операционные системы реализуют механизм переключения задач на основе системного таймера. Этот таймер периодически запускает подпрограмму, которая проверяет очередь задач и переключает выполнение с одной задачи на другую. Важно отметить, что прерывания от внешних устройств также работают в этой системе. Касательно рекомендаций книг, вот некоторые авторы и ресурсы: - Эндрю Таненбаум - Торвальдс - Русиновича - Helen Custer, David N Cutler - David A. Solomon Также можно ознакомиться с презентацией по данной теме и прикладной частью на указанных ресурсах.
Два конвейера помогают уменьшить накладные расходы на переключение контекста, но не увеличивают параллелизм, так как вычислительное ядро все равно остается одним.
В процессе нужно разделить понятия процесс и поток. Процесс можно рассматривать как контейнер для потоков, а не как активную единицу, которая выполняет код. Каждый процесс содержит по крайней мере один поток. Все программы, без исключения, начинают выполнение как однопоточный процесс, который может стать многопоточным путем создания дополнительных потоков. Операционная система планирует выполнение потоков, а не процессов.
Потоки не выполняют дополнительных действий для загрузки инструкций из кеша или основной памяти. Процессор самостоятельно загружает инструкции для потоков прозрачно.
Потоки в режиме ядра и пользовательском режиме отличаются только тем, в каких кольцах они исполняются. Потоки в режиме ядра работают в привилегированных кольцах, а потоки в режиме пользователя - в непривилегированных. Основное различие состоит в наборе процессорных инструкций и системных вызовов, доступных для потоков. Например, чтение файла с диска требует привилегий и выполняется потоком в режиме ядра.
На заре компьютеров, когда процессоры были еще большие, существовал только один поток выполнения задач. Чтобы достичь многозадачности, были разработаны операционные системы с механизмом вытеснения задач. Они работали так: когда одна задача завершалась, следующая в очереди получала возможность выполниться. Задача продолжала работать, пока не была завершена. Однако, проблемы возникали с операциями ввода-вывода, которые могли занимать много времени. Чтобы не ждать бесконечно долго, были введены прерывания, которые сигнализировали об окончании операции. Операционные системы начали использовать прерывания для вытеснения задач. Так появились многозадачные ОС. Тем не менее, ожидание прерываний на операции ввода-вывода могло занимать слишком много времени. В результате, было придумано генерировать прерывания с помощью таймера. Это был простой кварцевый генератор, подключенный к процессору. ОС начала использовать таймер для реализации реальной многозадачности. Система получала контроль через определенные промежутки времени, называемые "такты" или "клоки". Таким образом, все современные операционные системы используют механизм переключения задач на основе системного таймера. Он запускает подпрограмму каждые несколько миллисекунд, которая проверяет очередь задач и переключает выполнение с одной задачи на другую. Прерывания от внешних устройств также функционируют в системе. В молодости процессоров существовало только одно прерывание на все операции. Проще говоря, процессор мог работать только в одной задаче и не мог одновременно обрабатывать другие запросы.
Два конвейера позволяют сократить накладные расходы на переключение контекста. Однако они не увеличивают параллелизм, так как выполняются на одном вычислительном ядре. Процесс и поток - это два разных понятия. Процесс можно рассматривать как контейнер для потоков, а не как активную сущность, исполняющую код. В каждом процессе есть как минимум один поток. Все программы стартуют как однопоточный процесс и могут стать многопоточными, создавая дополнительные потоки. Операционная система планирует выполнение потоков, а не процессов. Потоки не выполняют дополнительных действий для загрузки инструкций из кеша или основной памяти. Процессор сам подгружает инструкции, и для потока это происходит прозрачно. Kernelspace и userspace потоки различаются только в привилегированности своего исполнения. Kernel потоки выполняются в привилегированных кольцах, а userspace потоки - в непривилегированных. В остальном они не отличаются друг от друга. Привилегированные кольца ограничивают доступ потока к определенным инструкциям и системным вызовам. Например, чтение файла с диска требует привилегий и выполняется в kernelspace потоке, когда userspace поток запрашивает эту операцию. Кооперативная многозадачность может быть реализована через green threads, которые представляют собой реализацию кооперативной многозадачности на уровне userspace. Некоторые языки программирования уже имеют готовые реализации green threads, названные по-разному, например, корутины в Python, горутины в Go или виртуальные потоки в Java. Теоретически возможно написать свою реализацию грин тредов без использования уже готовых языковых инструментов, но это обычно не имеет практического значения, кроме как для набора опыта. Под "kernel" обычно понимается ядро операционной системы, а не ядро процессора (которое называется core, а не kernel). Запуск потоков в kernelspace возможен только через написание модуля/драйвера ядра, обычным программам это недоступно. Параллелизм и многозадачность - это разные понятия. Многозадачность может быть реализована на процессоре с одним ядром, но параллелизм требует наличия нескольких вычислительных ядер.
Кооперативная многозадачность можно реализовать самостоятельно с помощью "green threads". Это понятие также реализовано в языках программирования под названиями "корутины" (Python), "горутины" (Go) или "виртуальные потоки" (Java). Они обеспечивают кооперативную многозадачность в пользовательском режиме. Возможно и написание собственной реализации "green threads" без использования готовых инструментов, но это имеет мало практической ценности, кроме как для освоения и накопления опыта.
Запуск потока в режиме ядра обычными программами невозможен, за исключением написания модуля или драйвера ядра. Под "kernel" обычно понимают ядро операционной системы, а не ядро процессора.
Пошаговая стратегия связана с многозадачностью, а не с параллелизмом. Процессор с одним ядром может быть многозадачным, но не параллельным.