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

В системе Linux потоки называются tasks (задачами) ,а не threads . Поток создается системным вызовом clone (). Данный системный вызов позволяет дочерней задаче использовать общее адресное пространство с родительской задачей (процессом).

Потоки в Java

Как уже отмечалось, Java – первая платформа для разработки программ, в которой многопоточность поддержана на уровне языка и базовых библиотек. Потоки в Java могут быть созданы следующими способами:

  • Как расширения класса Thread
  • Как классы, реализующие интерфейс Runnable , который содержит единственный метод run – исполняемое тело потока.

Потоки в Java управляются JVM . Возможно создание групп потоков и иерархии таких групп.

Возможные состояния потоков в Java изображены на рис. 10.7 . Подобно потокам в ОС, поток в Java создается и находится в состоянии новый , затем – выполняемый ; при вызове методов типа wait, sleep и др. поток переходит в состояние ожидания; при завершении метода run поток завершается.

Ключевые термины

Mac C- threads – пользовательские потоки в системе MacOS.

POSIX Pthreads – потоки, специфицированные стандартом POSIX и используемые в POSIX -приложениях.

Solaris threads – пользовательские потоки в ОС Solaris.

Thread – класс , представляющий поток , в языке Java .

Атрибуты потока – совокупность атрибутов POSIX -потока, описываемая типом pthread_attr_t .

Группа потоков ( thread group ) – совокупность потоков, имеющей свое собственное имя, над потоками которой определены групповые операции .

Задача (task) – название потока в Linux.

Исключение (exception) – высокоуровневый механизм обработки ошибочных ситуаций в объектно-ориентированных языках и операционных системах.

Локальные данные потока (thread-local storage - TLS) – данные, принадлежащие только определенному потоку и используемые только этим потоком.

Модель многопоточности – способ отображения пользовательских потоков в потоки ядра.

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

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

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

Мьютекс (mutex) – аналог семафоров, обеспечивающий взаимное исключение , используемый в операционных системах.

Облегченный процесс (lightweight process) – процесс, работающий в общем пространстве виртуальной памяти с процессом-родителем.

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

Поток пользовательского уровня (user thread) - высокоуровневый поток , операции над которым включены в интерфейс пользователя ОС.

Поток ядра (kernel thread) - низкоуровневый системный поток , поддержанный и использующийся на уровне ядра операционной системы; используется для реализации потоков пользовательского уровня .

Пул потоков (ThreadPool) эффективный механизм структурирования потоков в группы в. NET .

Сигналы (в UNIX ) – низкоуровневый механизм обработки ошибочных ситуаций.

"Тяжеловесный" (heavyweight) процесс – название классического процесса, работающего в собственном адресном пространстве, в противоположность облегченному процессу .

Условная переменная (conditional variable) - синхронизирующий объект , используемый в операционных системах, с операциями wait и signal .

Краткие итоги

Многопоточность (multi- threading ) – современное направление программирования, особенно актуальное в связи с широким распространением параллельных компьютерных архитектур. Поток – особый вид процесса, выполняемый в общем адресном пространстве с процессом-родителем. Поток характеризуется своим стеком, потоком управления и значениями регистров. Облегченный процесс (lightweight process) – механизм, с помощью которого реализуются потоки в ОС.

Впервые понятие процесса, близкое современной концепции потока, было реализовано в системе "Эльбрус" в конце 1970-х гг. Многопоточность появилась в UNIX , затем – в Solaris и Windows NT. В различных ОС архитектуры библиотек поддержки многопоточности различаются. В Java -технологии, а вслед за ней – в. NET , впервые многопоточность была реализована на уровне языка и базовых библиотек.

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

Многопоточность ставит ряд интересных проблем: семантика системных вызовов fork и exec ; прекращение потоков; обработка сигналов ; структуризация потоков в группы; поддержка локальных данных потока ( TLS ); синхронизация потоков ; тупики (взаимная блокировка потоков) и их предотвращение.

POSIX threads (Pthreads) - стандартизация API для поддержки многопоточности для операционных систем типа UNIX . Поток характеризуется своим дескриптором и атрибутами. Для синхронизации потоков используются мьютексы и условные переменные.

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

В Windows 2000 используется модель многопоточности "один-один". Каждый поток содержит свой номер, набор регистров, отдельные стеки для пользовательских и системных процедур, локальную память потока ( TLS ).

В Linux потоки называются задачами (tasks) и создаются системным вызовом clone .

Потоки в Java поддержаны на уровне языка и базовых библиотек. Представляются объектами класса Thread и его подклассов . Управляются виртуальной машиной Java . Возможно создание групп потоков. Состояния потоков аналогичны используемым в ОС.

Набор для практики

Вопросы

  1. Что такое поток?
  2. Чем отличаются однопоточные и многопоточные процессы?
  3. В чем преимущества многопоточности?
  4. В какой системе впервые было реализовано понятие процесса, близкое современному понятию потока?
  5. В какой ОС многопоточность впервые появилась "официально"?
  6. На какой платформе разработки программ многопоточность впервые была реализована на уровне языка и базовых библиотек?
  7. Что такое пользовательские потоки?
  8. Что такое системные потоки и чем они отличаются от пользовательских?
  9. Какие существуют модели многопоточности?
  10. В чем суть модели много/много?
  11. В чем суть модели много/один?
  12. В чем суть модели один/один?
  13. Каковы проблемы многопоточности?
  14. Что такое сигнал и как он обрабатывается в многопоточной программе?
  15. Что такое исключение и как оно обрабатывается в многопоточной программе?
  16. Что такое группа потоков?
  17. Что такое пул потоков?
  18. Что такое локальная память (данные) потока?
  19. Что такое Pthread?
  20. Какими типами данных описывается поток в

Отличие от процессов

Потоки выполнения отличаются от традиционных процессов многозадачной операционной системы тем, что:

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

Многопоточность

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

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

Другим использованием многопоточности, применяемым даже для однопроцессорных систем, является возможность для приложения реагирования на ввод данных. В однопоточных программах, если основной поток выполнения заблокирован выполнением длительной задачи, всё приложение может оказаться в замороженном состоянии. Перемещая такие длительные задачи в рабочий поток , который выполняется параллельно с основным потоком, становится возможным для приложений продолжать реагировать на действия пользователя во время выполнения задач в фоновом режиме. С другой стороны, в большинстве случаев многопоточность не единственный способ сохранить чувствительность программы. То же самое может быть достигнуто через асинхронный ввод/вывод или сигналы в UNIX.

Операционные системы планируют выполнение потоков одним из двух способов:

  1. Приоритетная многопоточность , вообще говоря, считается более совершенным подходом, так как она позволяет операционной системе определить, когда должно происходить переключение контекста. Недостаток приоритетной многопоточности состоит в том, что система может сделать переключение контекста в неподходящее время, что приводит к инверсии приоритета и другим негативным эффектам, которых можно избежать, применяя кооперативную многопоточность.
  2. Кооперативная многопоточность полагается на сами потоки и отказывается от управления, если потоки выполнения находятся в точках остановки. Это может создать проблемы, если поток выполнения ожидает ресурс, пока он не станет доступным.

До конца 1990-х процессоры в настольных компьютерах не имели поддержки многопоточности, так как переключение между потоками, как правило, происходило быстрее, чем полное переключение контекста процесса. Процессоры во встраиваемых системах , которые имеют более высокие требования к поведению в реальном времени , могут поддерживать многопоточность за счёт уменьшения времени на переключение между потоками, возможно, путём распределения выделенных регистровых файлов для каждого потока выполнения, вместо сохранения/восстановления общего регистрового файла. В конце 1990-х идея выполнения инструкций нескольких потоков одновременно, известная как одновременная многопоточность, под названием Hyper-Threading, достигла настольных компьютеров с процессором Intel Pentium 4 . Потом она была исключена из процессоров архитектуры Intel Core и Core 2 , но позже восстановлена в архитектуре Core i7 .

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

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

Процессы, потоки выполнения ядра, пользовательские потоки и файберы

Процесс является «самой тяжёлой» единицей планирования ядра. Собственные ресурсы для процесса выделяются операционной системой. Ресурсы включают память, дескрипторы файлов, разъёмы, дескрипторы устройств и окна. Процессы используют адресное пространство и файлы ресурсов в режиме разделения времени только через явные методы, такие как наследование дескрипторов файлов и сегментов разделяемой памяти. Процессы, как правило, предварительно преобразованы к многозадачному способу выполнения.

Потоки выполнения ядра относятся к «лёгким» единицам планирования ядра. Внутри каждого процесса существует по крайней мере один поток выполнения ядра. Если в рамках процесса могут существовать несколько потоков выполнения ядра, то они совместно используют общую память и файл ресурсов. Если процесс выполнения планировщика операционной системы является приоритетным, то потоки выполнения ядра тоже являются приоритетно многозадачными. Потоки выполнения ядра не имеют собственных ресурсов, за исключением стека вызовов , копии регистров процессора , включая счётчик команд , и локальную память потока выполнения (если она есть). Ядро может назначить по одному потоку выполнения для каждого логического ядра системы (поскольку каждый процессор разделяет сам себя на несколько логических ядер, если он поддерживает многопоточность, либо поддерживает только одно логическое ядро ​​на каждое физическое ядро, если не поддерживает многопоточность), а может выполнять свопинг заблокированных потоков выполнения. Однако потоки выполнения ядра требует гораздо больше времени, чем требуется на свопинг пользовательских потоков выполнения.

Потоки выполнения иногда реализуются в пользовательском пространстве библиотек, в этом случае они называются пользовательскими потоками выполнения . Ядро не знает о них, так что они управляются и планируются в пользовательском пространстве. В некоторых реализациях пользовательские потоки выполнения основываются на нескольких верхних потоках выполнения ядра , чтобы использовать преимущества многопроцессорных машин (модели M:N). В данной статье под термином «поток выполнения» по умолчанию (без квалификатора «ядра» или «пользовательский») имеется в виду «поток выполнения ядра». Пользовательские потоки выполнения, реализованные с помощью виртуальных машин , называют также «зелёными потоками выполнения». Пользовательские потоки выполнения, как правило, можно быстро создавать, и ими легко управлять, но они не могут использовать преимущества многопоточности и многопроцессорности. Они могут блокироваться, если все связанные с ним потоки выполнения ядра заняты, даже если некоторые пользовательские потоки готовы к запуску.

Файберы являются ещё более «лёгкими» блоками планирования, относящимися к кооперативной многозадачности : выполняющийся файбер должен явно «уступить» право другим файберам на выполнение, что делает их реализацию гораздо легче, чем реализацию потоков выполнения ядра ​​или пользовательских потоков выполнения. Файберы могут быть запланированы для запуска в любом потоке выполнения внутри того же процесса. Это позволяет приложениям получить повышение производительности за счет управления планированием самого себя, вместо того чтобы полагаться на планировщик ядра (который может быть не настроен на такое применение). Параллельные среды программирования, такие как OpenMP , обычно реализуют свои задачи посредством файберов.

Сущность потока выполнения и файбера

Одновременность и структуры данных

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

Чтобы избежать этого, прикладные программные интерфейсы (API) потоков выполнения предлагают примитивы синхронизации , такие как мьютексы , для блокировки структур данных от одновременного доступа. На однопроцессорных системах поток выполнения, обратившийся к заблокированному мьютексу, должен остановить работу и, следовательно, инициировать переключение контекста. На многопроцессорных системах поток выполнения может вместо опроса мьютекса произвести захват спинлока . Оба этих способа могут снижать производительность и вынуждать процессор в SMP-системах конкурировать за шину памяти, особенно если уровень модульности блокировок слишком высокий.

Ввод/вывод и планирование

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

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

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

N:1 (потоки выполнения уровня пользователя)

В модели N:1 предполагается, что все потоки выполнения уровня пользователя отображаются на единую планируемую сущность уровня ядра, и ядро ничего не знает о составе прикладных потоков выполнения. При таком подходе переключение контекста может быть сделано очень быстро, и, кроме того, он может быть реализован даже на простых ядрах, которые не поддерживают многопоточность. Однако, одним из главных недостатков его является то, что в нём нельзя извлечь никакой выгоды из аппаратного ускорения на многопоточных процессорах или многопроцессорных компьютерах, потому что только один поток выполнения может быть запланирован на любой момент времени. Эта модель используется в GNU Portable Threads.

M:N (смешанная потоковость)

В модели M:N некоторое число N прикладных потоков выполнения отображаются на некоторое число M сущностей ядра или «виртуальных процессоров». Модель является компромиссной между моделью уровня ядра («1:1») и моделью уровня пользователя («N:1»). Вообще говоря, «M:N» потоковость системы являются более сложной для реализации, чем ядро или пользовательские потоки выполнения, поскольку изменение кода как для ядра, так и для пользовательского пространства не требуется. В M:N реализации библиотека потоков отвечает за планирование пользовательских потоков выполнения на имеющихся планируемых сущностях. При этом переключение контекста потоков делается очень быстро, поскольку модель позволяет избежать системных вызовов. Тем не менее, увеличивается сложность и вероятность инверсии приоритетов, а также неоптимальность планирования без обширной (и дорогой) координации между пользовательским планировщиком и планировщиком ядра.

Реализации

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

Примеры реализаций потоков на уровне ядра

  • Light Weight Kernel Threads (LWKT) в различных версиях BSD
  • Потоковость MxN
  • Библиотека потоков POSIX (NPTL) для Linux , реализация стандарта POSIX Threads
  • Apple Multiprocessing Services, врсия 2.0 и последующие, использует встроенное микроядро в Mac OS 8.6, в более поздних версиях сделана модификация с целью последующего сопровождения.
  • Windows начиная с Windows 95 , Windows NT и после них.

Примеры реализаций потоков на уровне пользователя

  • GNU Portable Threads
  • FSU Pthreads
  • Thread Manager компании Apple
  • REALbasic (включая API для совместного использования потоков)
  • Netscape Portable Runtime (включая реализацию файберов в пользовательском пространстве)

Примеры реализаций смешанных потоков

  • «Scheduler activations» используется в собственной библиотеке приложений потоков POSIX для NetBSD (модель M:N в противоположность модели 1:1 ядра или модели приложений пользовательского пространства)
  • Marcel из проекта PM2
  • ОС для суперкомпьютера Tera/Cray MTA

Примеры реализаций файберов

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

Поддержка языков программирования

Многие языки программирования поддерживают потоки иначе. Большинство реализаций С и С++ сами по себе не обеспечивают прямой поддержки потоков, но обеспечивают доступ к потокам, предоставляемым операционной системой, через API. Некоторые языки программирования более высокого уровня (как правило, кросс-платформенные), такие как Java, Python, и.NET, предоставляют потоковость разработчику в виде абстрактной специфической платформы, отличающейся от реализации потоков в среде выполнения разработчика. Ряд других языков программирования также пытаются полностью абстрагировать концепцию параллелизма и потоковости от разработчика (Cilk , OpenMP , MPI …). Некоторые языки разрабатываются специально для параллелизма (Ateji PX, CUDA).

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

См. также

Примечания

Литература

  • David R. Butenhof. Programming with POSIX Threads. Addison-Wesley. ISBN 0-201-63392-2
  • Bradford Nichols, Dick Buttlar, Jacqueline Proulx Farell. Pthreads Programming. O’Reilly & Associates. ISBN 1-565-92115-1
  • Charles J. Northrup. Programming with UNIX Threads. John Wiley & Sons. ISBN 0-47-113751-0
  • Mark Walmsley. Multi-Threaded Programming in C++. Springer. ISBN 1-852-33146-1
  • Paul Hyde. Java Thread Programming. Sams. ISBN 0-67-231585-8
  • Bill Lewis. Threads Primer: A Guide to Multithreaded Programming. Prentice Hall. ISBN 0-13-443698-9
  • Steve Kleiman, Devang Shah, Bart Smaalders. Programming With Threads, SunSoft Press. ISBN 0-13-172389-8
  • Pat Villani. Advanced WIN32 Programming: Files, Threads, and Process Synchronization. Harpercollins Publishers. ISBN 0-87-930563-0
  • Jim Beveridge, Robert Wiener. Multithreading Applications in Win32. Addison-Wesley. ISBN 0-20-144234-5
  • Thuan Q. Pham, Pankaj K. Garg. Multithreaded Programming with Windows NT. Prentice Hall. ISBN 0-13-120643-5
  • Len Dorfman, Marc J. Neuberger. Effective Multithreading in OS/2. McGraw-Hill Osborne Media. ISBN 0-07-017841-0
  • Alan Burns, Andy Wellings. Concurrency in ADA. Cambridge University Press. ISBN 0-52-162911-X
  • Uresh Vahalia. Unix Internals: the New Frontiers. Prentice Hall. ISBN 0-13-101908-2
  • Alan L. Dennis. .Net Multithreading. Manning Publications Company. ISBN 1-930-11054-5
  • Tobin Titus, Fabio Claudio Ferracchiati, Srinivasa Sivakumar, Tejaswi Redkar, Sandra Gopikrishna. C# Threading Handbook. Peer Information. ISBN 1-861-00829-5
  • Tobin Titus, Fabio Claudio Ferracchiati, Srinivasa Sivakumar, Tejaswi Redkar, Sandra Gopikrishna. Visual Basic .Net Threading Handbook. Wrox Press. ISBN 1-861-00713-2

Ссылки

  • Binildas C. A. Query by Slice, Parallel Execute, and Join: A Thread Pool Pattern in Java
  • Herb Sutter. The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software
  • Multithreading в каталоге ссылок Open Directory Project (dmoz).
  • Daniel Robbins. POSIX threads explained

Модели многопоточности. Реализация многопоточности в ОС, как и многих других возможностей, имеет несколько уровней абстракции. Самый высокий из них – пользовательский уровень. С точки зрения пользователя и его программ, управление потоками реализовано через библиотеку потоков пользовательского уровня (user threads). Подробнее конкретные операции над пользовательскими потоками будут рассмотрены немного позже. Пока отметим лишь, что существует несколько моделей потоков пользовательского уровня, среди которых:

  • POSIX Pthreads – потоки, специфицированные стандартом POSIX и используемые в POSIX-приложениях (рассмотрены позже в данной лекции);
  • Mac C-threads – пользовательские потоки в системе MacOS;
  • Solaris threads – пользовательские потоки в ОС Solaris (рассмотрены позже в данной лекции).

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

  • Windows 95/98/NT/2000/XP/2003/2008/7;
  • Solaris;
  • Tru64 UNIX;
  • BeOS;
  • Linux.

Существуют различные модели многопоточности – способы отображения пользовательских потоков в потоки ядра. Теоретически возможны (и на практике реализованы) следующие модели многопоточности:

Модель много / один (many-to-one) – отображение нескольких пользовательских потоков в один и тот же поток ядра. Используется в операционных системах, не поддерживающих множественные системные потоки (например, с целью экономии памяти). Данная модель изображена на рис. 10.2 .

Рис. 10.2. Схема модели многопоточности "много / один".

Модель один / один (one-to-one) – взаимно-однозначное отображение каждого пользовательского потока в определенный поток ядра. Примеры ОС, использующих данную модель, - Windows 95/98/NT/2000/XP/2003/2008/7; OS/2. Данная модель изображена на рис. 10.3 .

Рис. 10.3. Схема модели многопоточности "один / один".

Модель много / много (many-to-many) – модель, допускающая отображение нескольких пользовательских потоков в несколько системных потоков. Такая модель позволяет ОС создавать большое число системных потоков. Характерным примером ОС, использующей подобную модель, является ОС Solaris, а также Windows NT / 2000 / XP / 2003 / 2008 / 7 с пакетом ThreadFiber . Данная модель изображена на рис. 10.4 .

Рис. 10.4. Схема модели многопоточности "много / много".

Конец работы -

Эта тема принадлежит разделу:

В лекции рассматриваются понятие потока thread и многопоточное выполнение multi-threading

В лекции рассматриваются понятие потока thread и многопоточное выполнение multi threading модели многопоточности пользовательские потоки и.. содержание введение однопоточные и многопоточные процессы история многопоточности пользовательские..

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ:

Что будем делать с полученным материалом:

Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Все темы данного раздела:

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

История многопоточности
Как небезынтересно отметить, один из первых шагов на пути к широкому использованию многопоточности, по-видимому, был сделан в 1970-е годы советскими разработчиками компьютерной аппаратуры и програм

Проблемы многопоточности
Многопоточность – весьма сложная, еще не полностью изученная и, тем более, не полностью формализованная область, в которой имеется много интересных проблем. Рассмотрим некоторые из них.

Потоки и процессы в Solaris
В ОС Solaris, как уже было отмечено, используется модель потоков много / много. Кроме того, в системе используется также уже известное нам понятие облегченный процесс (ligh

Потоки в Java
Как уже отмечалось, Java – первая платформа для разработки программ, в которой многопоточность поддержана на уровне языка и базовых библиотек. Потоки в Java могут быть созданы следующими способами:

Ключевые термины
Mac C-threads – пользовательские потоки в системе MacOS. POSIX Pthreads – потоки, специфицированные стандартом POSIX и используемые в POSIX-приложениях. Solaris threads – пользова

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

Краткие итоги
Многопоточность (multi-threading) – современное направление программирования, особенно актуальное в связи с широким распространением параллельных компьютерных архитектур. Поток – особый вид процесс

Вопросы
Что такое поток? Чем отличаются однопоточные и многопоточные процессы? В чем преимущества многопоточности? В какой системе впервые было реализовано понятие процесса

Упражнения
Проанализируйте и опишите преимущества, недостатки и проблемы многопоточности. Реализуйте модель многопоточности один/один. Реализуйте модель многопоточности много/один.

Темы для курсовых работ, рефератов, эссе
История концепции потока и многопоточности в операционных системах и языках программирования (реферат). Обзор многопоточности в UNIX, Linux, Solaris (реферат). Обзор многопо

Хотя добросовестное и регулярное проведение сплит-тестов может дать до 10% увеличения конверсии, существуют другие стратегии, способные приносить более ощутимые результаты. В этой статье мы рассмотрим одну из них, основанную на «капитальном ремонте» офферов и структуры маркетинговых воронок с учетом (user flow), проходящего через сайт.

Вашему вниманию — кейс от Бреда Смита (Brad Smith), являющегося одним из партнеров-основателей агентства Codeless Interactive и завсегдатаем таких проектов, как Kissmetrics, WordStream, AdEspresso и др. Он описал реальные примеры и пошаговый процесс оптимизации пользовательского потока . По результатам внедренных им мероприятий был достигнут 166% прирост новых лидов в течение 3 месяцев (см. иллюстрацию и комментарий ниже):

Результаты оптимизации пользовательского потока за 3 месяца по сравнению с предыдущим периодом (на средней части картинки показано, что количество привлеченных новых лидов (Contacts) увеличилось с 574 до 1 528, что составляет 166.2% рост)

Почему сплит-тестирование не всегда приносит ощутимый результат?

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

Однако зачастую такая радужная ситуация характерна только для частных случаев. Общая же картина на практике выглядит несколько иначе.

1. Во-первых, «крошечные изменения» в подавляющем большинстве приводят к «крошечным результатам» (если таковые вообще имеются). Более того, полученные в ходе сплит-тестирования результаты показывают одну стойкую, но неутешительную тенденцию: со временем показатели конверсии «откатываются» к средним значениям (см. график и комментарий ниже). Такой вывод был сделан сервисом PPC-аналитики WordStream на основании анализа деятельности тысяч аккаунтов контекстной рекламы AdWords, годовой рекламный бюджет которых составил свыше $3 000 000 000.

Пример результатов А/Б-теста: на графике синим цветом показан всплеск роста конверсии в начале тестирования и постепенное снижение показателей до среднего уровня, которое произошло в течение определенного временного промежутка

2. Во-вторых, практика тестирования требует наличия определенного объема данных для анализа. Это нужно, чтобы выборка считалась репрезентативной (достоверной). Например, если ваша посадочная страница не генерирует за месяц хотя бы 1 000 подписчиков, то вы не можете тестировать ее элементы. Точнее говоря, конечно же, это возможно, но полученные результаты нельзя будет считать достоверными из-за недостаточного объема данных. Другой пример: вы проводите А/Б-тест, имея 500 конверсий в месяц; результаты теста дают показатель 250 на 250 по испытываемым вариантам. Очевидно, что такой исход событий не позволяет выявить победителя. Нужен больший объем выборки.

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

Но и это еще не все…

Сплит-тесты почти никогда не могут обеспечить значительных результатов, так как в чистом виде приоритетная сфера их применения лежит в плоскости поверхностных изменений. Само по себе сплит-тестирование не затрагивает предварительного исследования элементов лендинга и не может дать ответ на вопрос о том, какой раздел landing page следует тестировать в первую очередь. На практике это означает, что маркетолог тратит уйму времени и сил на то, что является лишь крохотной частью всего процесса конверсии, пренебрегая более широким анализом того, что именно происходило до и после нажатия СТА-кнопки в лид-форме.

Как уже отмечалось выше, в качестве альтернативы можно использовать CRO стратегию, позволяющую получить более чем 10%-ный прирост коэффициента конверсии, фокусируясь при этом не на мелочах, а на усовершенствовании всего пользовательского потока, или так называемой « ».

Как работает оптимизация пользовательского потока?

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

— слева (для сайта электронной коммерции): контекстная реклама → товарный лендинг или карточка товара в интернет-магазине → покупка товара;
— справа (для сайта с платной подпиской или посадочной страницы): входящий трафик из социальных сетей → посадочная страница → подписка на email-рассылку

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

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

Squarespace предлагает красивые шаблоны, которые могут использоваться в различных рыночных нишах. Однако общий минус всех подобных конструкторов состоит в недостатке опций, позволяющих настроить работу сайта или landing page с учетом индивидуальных особенностей конкретного проекта

При этом зачастую упускается из виду (или умалчивается) один очень важный момент: насколько эффективно эти внешне красивые страницы могут взаимодействовать в рамках всего веб-ресурса.

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

При идеальном стечении обстоятельств такой пользовательский опыт может позволить отдельным посетителям найти то, за чем они пришли, и совершить покупку здесь и сейчас. Однако не стоит забывать, что по данным авторитетного маркетингового агентства Moz наиболее лояльными клиентами становятся те, кто посетил сайт порядка 10 раз, а не совершил конверсионное действие в первые 1-3 визита.

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

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

Но если вы начнете анализировать пользовательские потоки, то сможете неоднократно убедиться, что многие люди даже не заходят на главную страницу. Они либо переходят с объявления контекстной рекламы прямо на landing page, либо вводят в поисковую систему коммерческий запрос и направляются сразу на товарный лендинг или страницу с описанием запрашиваемой услуги.

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

Три примера пользовательских потоков, где в качестве отправных точек выступают разные источники:
— слева: ссылка с результатов выдачи поисковых систем → landing page → подписка на рассылку;
— в центре: прямая ссылка на сайт из закладок или введенная прямо в адресную строку браузера → главная страница → страница с описанием товара или услуги → добавление в корзину → оплата;
— справа: объявление контекстной рекламы → лендинг → покупка

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

Как анализировать пользовательский поток вашего сайта?

Итак, одним из наилучших способов повышения конверсии лендинга является приведение в соответствие рекламного объявления и оффера на посадочной странице. Это означает, что человек, вводящий запрос в поисковую систему, видит релевантное запросу контекстное объявление, и, кликая по нему, он попадает на landing page, контент которой полностью соответствует его содержанию. Таким образом посетитель получает именно то, что он запрашивал в поисковике.

Оптимизация пользовательского потока происходит приблизительно по такой же схеме за исключением того, что вы расширяете этот процесс, перенося его на весь путь потенциального клиента: начиная от источника трафика и заканчивая путешествием по сайту в «точку назначения». При этом нужно связывать каждую веб-страницу — или отдельное письмо серийной (follow-up) рассылки — с предыдущей.

Вот примерный алгоритм того, как это может выглядеть на практике.

Шаг #1. Определите, откуда приходят пользователи (чтобы понять, что они ищут)

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

Чтобы смоделировать путешествие потребителя применительно к определенному онлайн-бизнесу, можно использовать сервис Customer Journey to Online Purchase от компании Google, помогающий выяснить, какие маркетинговые каналы чаще всего используют пользователи в той или иной маркетинговой нише (см. иллюстрацию и комментарий ниже):

Пример интерфейса Customer Journey to Online Purchase, иллюстрирующего, какие каналы используют потребители небольших (опция «Small») сайтов электронной коммерции (опция «Shopping»), действующих с таргетингом на США (опция «The USA»)

Комментарий к иллюстрации . Перечисленные выше опции можно задавать применительно к разным сферам и географическим локациям веб-сайтов. Чем левее на графике канал, тем менее готовым к покупке будет приходящий из него посетитель. На приведенном примере таковыми являются пользователи, привлеченные из органической выдачи поисковиков (Organic Research). Наиболее горячая целевая аудитория в этой нише — те, кто переходят на сайт по прямой ссылке (Direct), вводя ее в адресную строку браузера или активируя ее из закладок. Поэтому канал Direct расположен крайним справа. Подобным же образом анализируются , показанные ближе к центру графика.

По словам разработчиков Customer Journey to Online Purchase, исходными данными для этого сервиса являются результаты анализа миллионов пользовательских взаимодействий, собираемых Google Analytics.

Поэтому логичным продолжением этого шага оптимизации пользовательских потоков на лендинге или сайте должно быть рассмотрение собранных в системе Google Analytics данных вашего проекта (см. колонку «Источники/Каналы» (Sources/Mediums)). Вот как это может выглядеть на реальном примере:

Несложно заметить, что большинство пользователей приходят на сайт из первых 3 источников: органическая выдача поисковой системы (в таблице — «google/organic»), переходы по прямым ссылкам (в таблице — «direct») и платный поисковый трафик (в таблице — «google/cpc»).

Если наложить информацию об источниках трафика на данные о популярных страницах — для этого в системе Google Analytics есть специальный отчет «Top Content»,— то можно визуализировать и проследить, как перемещаются по сайту посетители, впервые привлеченные на веб-ресурс:

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

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

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

2. Второй сегмент — это люди, привлекаемые с помощью платного поискового трафика. Они сразу направляются на landing page. С этой группой все ясно и понятно.

Шаг #2. Проанализируйте, какие элементы посещаемых страниц работают, а какие — нет

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

Эта работа предполагает построение так называемой системы микроконверсий — небольших взаимодействий и серий писем, которые получает человек, последовательно переходя от одной страницы или подписной формы (opt-in) к следующей (см. схему и комментарий ниже):

Схема, иллюстрирующая систему микроконверсий, которую должен пройти посетитель, прежде чем перейти на более высокий уровень лояльности: (1) главная страница → (2) переход на вложенную страницу через меню сайта → (3) реакция на полезный контент → (4) подписка на лендинге, «заточенном» под посетителей верхнего уровня воронки (TOFU) → (5) благодарственная страница с новым оффером (для перевода на средний уровень воронки (MOFU)) и email с полезным контентом → (6) переход и подписка на лендинге, «заточенном» под посетителей среднего уровня воронки (MOFU) → (7) благодарственная страница с новым оффером (для перевода на нижний уровень воронки (BOFU)) и email с полезным контентом → (8) лояльный подписчик и вход в продажу

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

Представленная выше схема может показаться слишком усложненной, однако практика показывает, что в подавляющем большинстве случаев необходимо 6-8 «касаний» с посетителем, чтобы добиться окончательной конверсии в покупку. Игнорирование этого принципа часто можно наблюдать, когда через настроенные в Facebook или ВКонтакте рекламные объявления холодный трафик направляется сразу на landing page с коммерческим оффером. Оптимизация пользовательского потока в таком случае предполагает внедрение так называемой системы взращивания клиентов (lead nurturing) — специально разработанной кампании (drip campaign) — включая последовательную серию писем,— направленной на повышение лояльности новых посетителей сайта.

Когда проблема выявлена, остальное — дело техники. Например, можно использовать доступный функционал в соцсетях, чтобы автоматически добавлять новые контакты для дальнейшего взаимодействия с ними через сервисы почтовой рассылки или Saas-платформы автоматизации маркетинга (MailChimp, Infusionsoft, HubSpot и др.):

На иллюстрации показано, как с помощью полезной CRM AdEspresso настраивается автоматическое добавление новых контактов из Facebook в HubSpot для последующей работы с лидами

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

Для такого анализа лучше всего использовать специализированные сервисы, которые позволяют генерировать наглядные визуальные изображения (тепловые карты), характеризующие поведение онлайн-пользователей на исследуемом объекте. Зачастую такие кейсы являются более информативными, с ними легче работать и проще доносить полученные результаты до клиентов и начальства. Далее в статье будут рассмотрены примеры такого анализа, полученные с использованием соответствующего функционала SaaS-платформы CrazyEgg.

Например, чтобы выяснить, почему посетители главной страницы сайта, содержащей обилие информации, никак не реагируют на ее контент, можно использовать . Анализируя эту длинную страницу — см. иллюстрацию и комментарий ниже — можно увидеть, что ее никто не читает:

Карта прокрутки позволяет оценить, насколько далеко посетитель опускается вниз страницы в ходе изучения контента, задействуя скроллинг. Проиллюстрированные выше результаты показывают, что никто не переходит так называемую «линию сгиба» (below the fold), а читает лишь то, что представлено на первом экране

Чтобы интерпретировать представленную на картинке информацию, нужно обратить внимание на цветовую шкалу, расположенную в правом нижнем углу: чем «горячее» цвет, тем больше внимания пользователей привлекает окрашенная в него часть страницы, а чем «холоднее» — тем меньше посетителей добрались до соответствующей части веб-страницы или лендинга (как до дна голубого океана, куда почти никто не погружается).

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

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

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

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

Шаг #3. Оптимизируйте дизайн и контент страниц с учетом особенностей пользовательского потока

Что возникает в вашем воображении, когда вы слышите слово «дизайнер» (designer)? Большинство скажут, что это человек, создающий внешний вид лендинга. Однако у английского слова «designer» есть еще несколько значений, два из которых — конструктор, проектировщик. Поэтому (в глубинном смысле) дизайн посадочной страницы — это не то, как она выглядит, а то, как она работает .

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

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

На иллюстрации показана тепловая карта лендинга, внешний вид которого разрабатывался без учета того, какое конверсионное действие должен совершить пользователь

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

В противоположность этому, дизайн страницы, ориентированный на конкретное конверсионное действие, содержит один-два СТА-элемента, выделяющегося на общем фоне. В этом случае клики будут распределяться следующим образом:

На иллюстрации изображена таблица распределения кликов среди всех кликабельных элементов страницы (СТА-кнопки, текстовые ссылки, картинки и др.). В подавляющем большинстве случаев (45%) посетители кликают именно на СТА-кнопку (Download Now) в лид-форме. Это является показательным признаком конверсионной страницы

Если подавляющее большинство кликов на вашей посадочной странице приходится на СТА-кнопку, значит вы на правильном пути. Но если чувствуете, что в этом вопросе вам есть что улучшить, адаптируйте к своему бизнесу — практический материал из рубрики нашего блога, содержащей проверенные принципы и примеры дизайна landing page с высокой конверсией.

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

Например, чтобы решить, какую лид-форму — длинную или короткую — размещать на посадочной странице, нужно понимать особенности конкретного пользовательского потока:

  • если посетители относятся к категории TOFU (находятся в верхней части воронки и мало знакомы с брендом), то нужна форма с минимальным количеством полей для заполнения;
  • если же большая часть трафика представляют группу BOFU (находятся в нижней части воронки, уже получали полезный контент и лояльно относятся к бренду), то при необходимости можно использовать более подробную лид-форму.

Суровая реальность интернет-маркетинга такова, что не зная структуры пользовательского потока, бывает очень проблематично существенно повысить конверсию landing page. Поэтому нередко приходится переделывать уже готовый дизайн с учетом особенностей входящего трафика (см. иллюстрацию и комментарий ниже):

Обычно выделяют две общие категории потоков: потоки на уровне пользователя (user-level threads - ULT) и потоки на уровне ядра (kernel-level threads - KLT). Потоки второго типа в литературе иногда называются потоками, поддерживаемыми ядром, или облегченными процессами.

Потоки на уровне пользователя

В программе, полностью состоящей из ULT-потоков, все действия по управлению потоками выполняются самим приложением; ядро, по сути, и не подозревает о существовании потоков. На рис. 4.6,а проиллюстрирован подход, при котором используются только потоки на уровне пользователя. Чтобы приложение было многопоточным, его следует создавать с применением специальной библиотеки, представляющей собой пакет программ для работы с потоками на уровне ядра. Такая библиотека для работы с потоками содержит код, с помощью которого можно создавать и удалять потоки, производить обмен сообщениями и данными между потоками, планировать их выполнение, а также сохранять и восстанавливать их контекст.

Рис. 4.6. Потоки на пользовательском уровне и на уровне ядра

По умолчанию приложение в начале своей работы состоит из одного потока и его выполнение начинается как выполнение этого потока. Такое приложение вместе с составляющим его потоком размещается в едином процессе, который управляется ядром. Выполняющееся приложение в любой момент времени может породить новый поток, который будет выполняться в пределах того же процесса. Новый поток создается с помощью вызова специальной подпрограммы из библиотеки, предназначенной для работы с потоками. Управление к этой подпрограмме переходит в результате вызова процедуры. Библиотека потоков создает структуру данных для нового потока, а потом передает управление одному из готовых к выполнению потоков данного процесса, руководствуясь некоторым алгоритмом планирования. Когда управление переходит к библиотечной подпрограмме, контекст текущего потока сохраняется, а когда управление возвращается к потоку, его контекст восстанавливается. Этот контекст в основном состоит из содержимого пользовательских регистров, счетчика команд и указателей стека.

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

  1. Приложение, в котором выполняется поток 2, может произвести системный вызов, например запрос ввода-вывода, который блокирует процесс В. В результате этого вызова управление перейдет к ядру. Ядро вызывает процедуру ввода-вывода, переводит процесс В в состояние блокировки и передает управление другому процессу. Тем временем поток 2 процесса В все еще находится в состоянии выполнения в соответствии со структурой данных, поддерживаемой библиотекой потоков. Важно отметить, что поток 2 не выполняется в том смысле, что он работает с процессором; однако библиотека потоков воспринимает его как выполняющийся. Соответствующие диаграммы состояний показаны на рис. 4.7,6.
  2. В результате прерывания по таймеру управление может перейти к ядру; ядро определяет, что интервал времени, отведенный выполняющемуся в данный момент процессу В, истек. Ядро переводит процесс В в состояние готовности и передает управление другому процессу. В это время, согласно структуре данных, которая поддерживается библиотекой потоков, поток 2 процесса В по-прежнему будет находиться в состоянии выполнения. Соответствующие диаграммы состояний показаны на рис. 4.7,в.
  3. Поток 2 достигает точки выполнения, когда ему требуется, чтобы поток 1 процесса В выполнил некоторое действие. Он переходит в заблокированное состояние, а поток 1 - из состояния готовности в состояние выполнения. Сам процесс остается в состоянии выполнения. Соответствующие диаграммы состояний показаны на рис. 4.7,г.


Рис. 4.7. Примеры взаимосвязей между состояниями потоков пользовательского уровня и состояниями процесса

В случаях 1 и 2 (см. рис. 4.7,6 и в) при возврате управления процессу В возобновляется выполнение потока 2. Заметим также, что процесс, в котором выполняется код из библиотеки потоков, может быть прерван либо из-за того, что закончится отведенный ему интервал времени, либо из-за наличия процесса с более высоким приоритетом. Когда возобновится выполнение прерванного процесса, оно продолжится работой процедуры из библиотеки потоков, которая завершит переключение потоков и передаст управление новому потоку процесса.

Использование потоков на пользовательском уровне обладает некоторыми преимуществами перед использованием потоков на уровне ядра. К этим преимуществам относятся следующие:

  1. Переключение потоков не включает в себя переход в режим ядра, так как структуры данных по управлению потоками находятся в адресном пространстве одного и того же процесса. Поэтому для управления потоками процессу не нужно переключаться в режим ядра. Благодаря этому обстоятельству удается избежать накладных расходов, связанных с двумя переключениями режимов (пользовательского режима в режим ядра и обратно).
  2. Планирование производится в зависимости от специфики приложения. Для одних приложений может лучше подойти простой алгоритм планирования по круговому алгоритму, а для других - алгоритм планирования, основанный на использовании приоритета. Алгоритм планирования может подбираться для конкретного приложения, причем это не повлияет на алгоритм планирования, заложенный в операционной системе.
  3. Использование потоков на пользовательском уровне применимо для любой операционной системы. Для их поддержки в ядро системы не потребуется вносить никаких изменений. Библиотека потоков представляет собой набор утилит, работающих на уровне приложения и совместно используемых всеми приложениями.

Использование потоков на пользовательском уровне обладает двумя явными недостатками по сравнению с использованием потоков на уровне ядра.

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

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

Потоки на уровне ядра

В программе, работа которой полностью основана на потоках, работающих на уровне ядра, все действия по управлению потоками выполняются ядром. В области приложений отсутствует код, предназначенный для управления потоками. Вместо него используется интерфейс прикладного программирования (application programming interface - API) средств ядра, управляющих потоками. Примерами такого подхода являются операционные системы OS/2, Linux и W2K.
На рис. 4.6,6" проиллюстрирована стратегия использования потоков на уровне ядра. Любое приложение при этом можно запрограммировать как многопоточное; все потоки приложения поддерживаются в рамках единого процесса. Ядро поддерживает информацию контекста процесса как единого целого, а также контекстов каждого отдельного потока процесса. Планирование выполняется ядром исходя из состояния потоков. С помощью такого подхода удается избавиться от двух упомянутых ранее основных недостатков потоков пользовательского уровня. Во-первых, ядро может одновременно осуществлять планирование работы нескольких потоков одного и того же процесса на нескольких процессорах. Во-вторых, при блокировке одного из потоков процесса ядро может выбрать для выполнения другой поток этого же процесса. Еще одним преимуществом такого подхода является то, что сами процедуры ядра могут быть многопоточными.
Основным недостатком подхода с использованием потоков на уровне ядра по сравнению с использованием потоков на пользовательском уровне является то, что для передачи управления от одного потока другому в рамках одного и того же процесса приходится переключаться в режим ядра. Результаты исследований, проведенных на однопроцессорной машине VAX под управлением UNIX-подобной операционной системы, представленные в табл. 4.1, иллюстрируют различие между этими двумя подходами. Сравнивалось время выполнения таких двух задач, как (1) нулевое ветвление (Null Fork) - время, затраченное на создание, планирование и выполнение процесса/потока, состоящего только из нулевой процедуры (измеряются только накладные расходы, связанные с ветвлением процесса/потока), и (2) ожидание сигнала (Signal-Wait) - время, затраченное на передачу сигнала от одного процесса/потока другому процессу/потоку, находящемуся в состоянии ожидания (накладные расходы на синхронизацию двух процессов/потоков). Чтобы было легче сравнивать полученные значения, заметим, что вызов процедуры на машине VAX, используемой в этом исследовании, длится 7 us, а системное прерывание - 17 us. Мы видим, что различие во времени выполнения потоков на уровне ядра и потоков на пользовательском уровне более чем на порядок превосходит по величине различие во времени выполнения потоков на уровне ядра и процессов.

Таблица 4.1. Время задержек потоков (ка)

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

Комбинированные подходы

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

Другие схемы

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

Таблица 4.2. Соотношение между потоками и процессами

Соответствие нескольких потоков нескольким процессам

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

  1. Реализовать всю программу в виде единого процесса. Такой прямолинейный подход является вполне обоснованным. Недостатки этого подхода связаны с управлением памятью. Эффективно организованный как единое целое процесс может занимать в памяти много места, в то время как для подпрограммы ввода-вывода требуется относительно небольшое адресное пространство. Из-за того что подпрограмма ввода-вывода выполняется в адресном пространстве более объемной программы, во время выполнения ввода-вывода весь процесс должен оставаться в основной памяти, либо операция ввода-вывода будет выполняться с применением свопинга. То же происходит и в случае, когда и основная программа, и подпрограмма ввода-вывода реализованы в виде двух потоков в одном адресном пространстве.
  2. Основная программа и подпрограмма ввода-вывода реализуются в виде двух отдельных процессов. Это приводит к накладным затратам, возникающим в результате создания подчиненного процесса. Если ввод-вывод производится достаточно часто, то необходимо будет либо оставить такой подчиненный процесс активным на все время работы основного процесса, что связано с затратами на управление ресурсами, либо часто создавать и завершать процесс с подпрограммой, что приведет к снижению эффективности.
  3. Реализовать действия основной программы и подпрограммы ввода-вывода как единый поток. Однако для основной программы следует создать свое адресное пространство (свой домен), а для подпрограммы ввода-вывода - свое. Таким образом, поток в ходе выполнения программы будет переходить из одного адресного пространства к другому. Операционная система может управлять этими двумя адресными пространствами независимо, не затрачивая никаких дополнительных ресурсов на создание процесса. Более того, адресное пространство, используемое подпрограммой ввода-вывода, может использоваться совместно с другими простыми подпрограммами ввода-вывода.

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

Соответствие одного потока нескольким процессам

В области распределенных операционных систем (разрабатываемых для управления распределенными компьютерными системами) представляет интерес концепция потока как основного элемента, способного переходить из одного адресного пространства в другое (В последние годы активно исследуется тема перехода процессов и потоков из одного адресного пространства в другое (миграция). Эта тема рассматривается в главе 14, "Управление распределенными процессами". ). Заслуживают упоминания операционная система Clouds и, в особенности, ее ядро, известное под названием Ra . В качестве другого примера можно привести систему Emerald .

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

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



Закрытие ИП