Поток (вычисления) - Thread (computing)

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

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

История

Обсуждения впервые появились под названием "задачи" в Мультипрограммирование OS / 360 с переменным количеством задач (MVT) в 1967 году. Зальцер (1966) кредиты Виктор Александрович Высоцкий с термином «резьба».[2]

Популярность потоковой передачи возросла примерно в 2003 году, поскольку рост частоты ЦП сменился ростом числа ядер, что, в свою очередь, потребовало параллелизма для использования нескольких ядер.[3]

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

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

Процессы

На уровне ядра обработать содержит один или несколько потоки ядра, которые разделяют ресурсы процесса, такие как память и дескрипторы файлов: процесс - это единица ресурсов, а поток - это единица планирования и выполнения. Планирование ядра обычно выполняется в упреждающем или, что реже, совместно. На уровне пользователя такой процесс, как система времени выполнения может сам планировать несколько потоков выполнения. Если они не разделяют данные, как в Erlang, их обычно аналогичным образом называют процессами,[4] в то время как если они делятся данными, их обычно называют (пользователь) темы, особенно если запланировано заранее. Совместно запланированные пользовательские потоки известны как волокна; разные процессы могут по-разному планировать пользовательские потоки. Пользовательские потоки могут выполняться потоками ядра различными способами (один-к-одному, многие-к-одному, многие-ко-многим). Период, термин "легкий процесс "по-разному относится к пользовательским потокам или механизмам ядра для планирования пользовательских потоков в потоках ядра.

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

Потоки ядра

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

Пользовательские потоки

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

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

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

Распространенным решением этой проблемы (используемым, в частности, многими реализациями зеленых потоков) является предоставление API ввода-вывода, который реализует синхронный интерфейс с помощью внутреннего неблокирующего ввода-вывода и планирования другого пользовательского потока или волокна, пока Выполняется операция ввода-вывода. Аналогичные решения могут быть предусмотрены для других системных вызовов блокировки. В качестве альтернативы, программа может быть написана так, чтобы избежать использования синхронного ввода-вывода или других блокирующих системных вызовов (в частности, с использованием неблокирующего ввода-вывода, включая лямбда-продолжения и / или async /Ждите примитивы[5]).

Волокна

Волокна являются еще более легкой единицей планирования, которая совместно запланированный: работающее волокно должно явно "Уступать "чтобы позволить другому файлу работать, что делает их реализацию намного проще, чем ядро ​​или пользовательские потоки. Можно запланировать запуск волокна в любом потоке одного и того же процесса. Это позволяет приложениям повышать производительность, управляя расписанием самостоятельно, вместо того, чтобы полагаться на планировщик ядра (который может не быть настроен для приложения). Среды параллельного программирования, такие как OpenMP обычно реализуют свои задачи через волокна. Тесно связаны с волокнами сопрограммы, с той разницей, что сопрограммы являются конструкцией уровня языка, а волокна - конструкцией системного уровня.

Потоки против процессов за и против

Нитки отличаются от традиционных многозадачность Операционная система процессы несколькими способами:

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

Такие системы как Windows NT и OS / 2 говорят, что имеют дешево темы и дорогая процессы; в других операционных системах разница не так велика, кроме стоимости адресное пространство переключатель, который на некоторых архитектурах (особенно x86 ) приводит к резервный буфер перевода (TLB) промывка.

Преимущества и недостатки потоков по сравнению с процессами включают:

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

Планирование

Превентивное и совместное планирование

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

Одно- и многопроцессорные системы

До начала 2000-х годов большинство настольных компьютеров имели только один одноядерный процессор без поддержки аппаратные потоки, хотя потоки все еще использовались на таких компьютерах, потому что переключение между потоками, как правило, было быстрее, чем полное переключатели контекста. В 2002, Intel добавлена ​​поддержка одновременная многопоточность к Pentium 4 процессор, под названием Hyper Threading; в 2005 году они представили двухъядерный Pentium D процессор и AMD представил двухъядерный Athlon 64 X2 процессор.

Системы с одним процессором обычно реализуют многопоточность посредством квантование времени: the центральное процессорное устройство (CPU) переключается между разными программные потоки. Эта переключение контекста обычно происходит достаточно часто, чтобы пользователи воспринимали потоки или задачи как выполняющиеся параллельно (для популярных операционных систем серверов / настольных компьютеров максимальный временной отрезок потока, когда другие потоки ожидают, часто ограничивается 100-200 мс). На мультипроцессор или многоядерный система, несколько потоков могут выполняться в параллельно с каждым процессором или ядром, выполняющим отдельный поток одновременно; на процессоре или ядре с аппаратные потоки отдельные программные потоки также могут выполняться одновременно отдельными аппаратными потоками.

Модели с резьбой

1: 1 (потоки на уровне ядра)

Потоки, созданные пользователем в соответствии 1: 1 с планируемыми объектами в ядре[6] являются простейшей возможной реализацией потоковой передачи. OS / 2 и Win32 использовали этот подход с самого начала, пока Linux то обычная библиотека C реализует этот подход (через NPTL или старше LinuxThreads ). Этот подход также используется Солярис, NetBSD, FreeBSD, macOS, и iOS.

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

An NМодель: 1 подразумевает, что все потоки уровня приложения отображаются в один запланированный объект уровня ядра;[6] ядру ничего не известно о потоках приложения. При таком подходе переключение контекста может быть выполнено очень быстро, и, кроме того, оно может быть реализовано даже на простых ядрах, которые не поддерживают многопоточность. Однако одним из основных недостатков является невозможность использования аппаратного ускорения на многопоточный процессоры или мультипроцессор компьютеры: никогда не может быть запланировано более одного потока одновременно.[6] Например: если одному из потоков необходимо выполнить запрос ввода-вывода, весь процесс блокируется и преимущество потоковой передачи не может быть использовано. В Переносимые потоки GNU использует потоки на уровне пользователя, как и Государственные потоки.

M:N (гибридная резьба)

M:N отображает некоторые M количество потоков приложения на некоторые N количество сущностей ядра,[6] или «виртуальные процессоры». Это компромисс между уровнем ядра («1: 1») и уровнем пользователя («N: 1 ") threading. В общем,"M:N"многопоточные системы сложнее реализовать, чем ядра или пользовательские потоки, потому что требуются изменения как в ядре, так и в коде пользовательского пространства[требуется разъяснение ]. В реализации M: N библиотека потоков отвечает за планирование пользовательских потоков на доступных планируемых объектах; это делает переключение контекста потоков очень быстрым, так как позволяет избежать системных вызовов. Однако это увеличивает сложность и вероятность инверсия приоритета, а также субоптимальное планирование без обширной (и дорогостоящей) координации между планировщиком пользовательского пространства и планировщиком ядра.

Примеры гибридной реализации

  • Планировщик активаций используется более старыми версиями реализации библиотеки потоков POSIX для NetBSD ( M:N модель в отличие от 1: 1 модели реализации ядра или пользовательского пространства)
  • Легкие процессы используется более старыми версиями Солярис Операционная система
  • Марсель из PM2 проект.
  • ОС для Tera-Крей МТА-2
  • Microsoft Windows 7 планирование в пользовательском режиме[7][8]
  • В Компилятор Glasgow Haskell (GHC) для языка Haskell использует легкие потоки, которые запланированы для потоков операционной системы.

История потоковых моделей в системах Unix

SunOS 4.x реализовано легкие процессы или LWP. NetBSD 2.x + и DragonFly BSD реализовать LWP как потоки ядра (модель 1: 1). От SunOS 5.2 до SunOS 5.8, а также от NetBSD 2 до NetBSD 4 реализована двухуровневая модель, мультиплексирующая один или несколько потоков пользовательского уровня в каждом потоке ядра (модель M: N). SunOS 5.9 и новее, а также NetBSD 5 устранили поддержку пользовательских потоков, вернувшись к модели 1: 1.[9] Во FreeBSD 5 реализована модель M: N. FreeBSD 6 поддерживает как 1: 1, так и M: N, пользователи могут выбирать, какую из них следует использовать с данной программой, используя /etc/libmap.conf. Начиная с FreeBSD 7, по умолчанию стало 1: 1. FreeBSD 8 больше не поддерживает модель M: N.

Однопоточные и многопоточные программы

В компьютерное программирование, однопоточный это обработка одного команда вовремя.[10] В формальном анализе переменных ' семантика и состояние процесса, термин одинарная резьба может использоваться по-разному, чтобы означать "возврат в пределах одного потока", что является обычным для функциональное программирование сообщество.[11]

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

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

Потоки и синхронизация данных

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

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

Другие API синхронизации включают переменные состояния, критические разделы, семафоры, и мониторы.

Пулы потоков

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

Многопоточные программы против однопоточных программ за и против

Многопоточные приложения имеют следующие преимущества перед однопоточными:

  • Ответная реакция: многопоточность может позволить приложению реагировать на ввод. В однопоточной программе, если основной поток выполнения блокируется на длительной задаче, может показаться, что все приложение зависает. Перемещая такие длительные задачи в рабочий поток который выполняется одновременно с основным потоком выполнения, приложение может реагировать на ввод данных пользователем при выполнении задач в фоновом режиме. С другой стороны, в большинстве случаев многопоточность - не единственный способ сохранить отзывчивость программы. неблокирующий ввод / вывод и / или Сигналы Unix доступны для получения аналогичных результатов.[12]
  • Распараллеливание: приложения, желающие использовать многоядерные или многопроцессорные системы, могут использовать многопоточность для разделения данных и задач на параллельные подзадачи и позволить базовой архитектуре управлять тем, как потоки выполняются либо одновременно на одном ядре, либо параллельно на нескольких ядрах. Вычислительные среды GPU, такие как CUDA и OpenCL использовать модель многопоточности, в которой выполняются от десятков до сотен потоков параллельно по данным на большое количество ядер. Это, в свою очередь, позволяет лучше использовать систему и (при условии, что затраты на синхронизацию не съедают выгоду) может обеспечить более быстрое выполнение программы.

Многопоточные приложения имеют следующие недостатки:

  • Синхронизация сложность и связанные с этим ошибки: при использовании общих ресурсов, типичных для многопоточных программ, программист нужно быть осторожным, чтобы избежать условия гонки и другое неинтуитивное поведение. Чтобы данные можно было правильно обрабатывать, потокам часто требуется рандеву вовремя, чтобы обработать данные в правильном порядке. Потоки также могут потребовать взаимоисключающий операции (часто реализуются с использованием мьютексы ), чтобы предотвратить чтение или перезапись общих данных в одном потоке при изменении другим. Неосторожное использование таких примитивов может привести к тупиковые ситуации, лайвлоки или гонки над ресурсами. Так как Эдвард А. Ли написал: «Хотя потоки кажутся маленьким шагом от последовательных вычислений, на самом деле они представляют собой огромный шаг. Они отбрасывают наиболее важные и привлекательные свойства последовательных вычислений: понятность, предсказуемость и детерминизм. Потоки как модель вычислений, являются в высшей степени недетерминированными, и работа программиста сводится к сокращению этого недетерминизма ".[13]
  • Быть непроверенным. В общем, многопоточные программы недетерминированы и, как следствие, не поддаются тестированию. Другими словами, многопоточная программа может легко иметь ошибки, которые никогда не проявляются в тестовой системе, а проявляются только в производственной среде.[14][13] Этого можно избежать, ограничив взаимодействие между потоками определенными четко определенными шаблонами (такими как передача сообщений).
  • Затраты на синхронизацию. Поскольку переключение контекста потока на современных ЦП может стоить до 1 миллиона циклов ЦП,[15] это затрудняет написание эффективных многопоточных программ. В частности, особое внимание следует уделять тому, чтобы межпоточная синхронизация не была слишком частой.

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

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

  • IBM PL / I (F) включена поддержка многопоточности (так называемая многозадачность) еще в конце 1960-х, и это было продолжено в оптимизирующем компиляторе и более поздних версиях. Компилятор IBM Enterprise PL / I представил новую модель «потокового» API. Ни одна из версий не входила в стандарт PL / I.
  • Многие реализации C и C ++ поддержка потоковой передачи и предоставление доступа к встроенным API потоковой передачи операционной системы. Стандартизированный интерфейс для реализации потока Потоки POSIX (Pthreads), который представляет собой набор вызовов библиотеки C-функций. Поставщики ОС могут свободно реализовать интерфейс по своему желанию, но разработчик приложения должен иметь возможность использовать один и тот же интерфейс на нескольких платформах. Наиболее Unix платформы, включая Linux, поддерживают Pthreads. Microsoft Windows имеет собственный набор потоковых функций в process.h интерфейс для многопоточности, например beginthread.
  • Немного высший уровень (и обычно кросс-платформенный ) языки программирования, такие как Ява, Python, и .NET Framework языках, предоставляют разработчикам доступ к потокам, абстрагируя специфические для платформы различия в реализациях потоковой передачи во время выполнения. Несколько других языков программирования и языковых расширений также пытаются полностью абстрагироваться от концепции параллелизма и потоковой передачи от разработчика (Силк, OpenMP, Интерфейс передачи сообщений (MPI)). Некоторые языки вместо этого предназначены для последовательного параллелизма (особенно с использованием графических процессоров), не требуя параллелизма или потоков (Ateji PX, CUDA ).
  • Некоторые интерпретируемые языки программирования имеют реализации (например, Рубиновый МРТ для Руби, CPython для Python), которые поддерживают потоки и параллелизм, но не параллельное выполнение потоков из-за глобальная блокировка интерпретатора (ГИЛ). GIL - это блокировка взаимного исключения, удерживаемая интерпретатором, которая может помешать интерпретатору одновременно интерпретировать код приложения в двух или более потоках одновременно, что эффективно ограничивает параллелизм в многоядерных системах. Это ограничивает производительность в основном для потоков с привязкой к процессору, которые требуют процессора, и не сильно для потоков с привязкой к вводу-выводу или с привязкой к сети. Другие реализации интерпретируемых языков программирования, такие как Tcl используя расширение Thread, избегайте ограничения GIL, используя модель Apartment, в которой данные и код должны явно «совместно использоваться» между потоками. В Tcl у каждого потока есть один или несколько интерпретаторов.
  • В моделях программирования, таких как CUDA предназначен для параллельное вычисление данных, выполняется массив потоков тот же код параллельно, используя только его ID, чтобы найти данные в памяти. По сути, приложение должно быть спроектировано так, чтобы каждый поток выполнял одну и ту же операцию с разными сегментами памяти, чтобы они могли работать параллельно и использовать архитектуру GPU.
  • Языки описания оборудования такие как Verilog имеют другую модель потоков, которая поддерживает чрезвычайно большое количество потоков (для моделирования оборудования).

Смотрите также

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

  1. ^ Лэмпорт, Лесли (Сентябрь 1979 г.). «Как сделать многопроцессорный компьютер, который правильно выполняет многопроцессорные программы» (PDF). Транзакции IEEE на компьютерах. С-28 (9): 690–691. Дои:10.1109 / tc.1979.1675439. S2CID  5679366.
  2. ^ Управление трафиком в мультиплексной компьютерной системе, Джером Ховард Зальцер, Докторская диссертация, 1966 г., см. Сноску на странице 20.
  3. ^ Херб Саттер. «Бесплатный обед окончен: фундаментальный поворот к параллелизму в программном обеспечении».
  4. ^ "Erlang: 3.1 процессы".
  5. ^ Сергей Игнатченко. «Восемь способов обработки неблокирующего возврата в программах с передачей сообщений: от C ++ 98 через C ++ 11 к C ++ 20». CPPCON.
  6. ^ а б c d Ганье, Абрахам Зильбершатц, Питер Баер Галвин, Грег (2013). Понятия операционной системы (9-е изд.). Хобокен, штат Нью-Джерси: Wiley. С. 170–171. ISBN  9781118063330.
  7. ^ Марк Риттингхаус (23 декабря 2010 г.). «Агрегация системных вызовов для модели гибридного потока» (PDF). п. 10.
  8. ^ «Планирование в пользовательском режиме». Документы Microsoft. 30 мая 2018.
  9. ^ «Многопоточность в операционной среде Solaris» (PDF). 2002. Архивировано с оригинал (PDF) 26 февраля 2009 г.
  10. ^ Рауль Менендес; Дуг Лоу (2001). CICS Мураха для программиста на COBOL. Майк Мурач и партнеры. п. 512. ISBN  978-1-890774-09-7.
  11. ^ Питер Уильям О'Хирн; Р. Д. Теннент (1997). Алголоподобные языки. 2. Birkhäuser Verlag. п. 157. ISBN  978-0-8176-3937-2.
  12. ^ Сергей Игнатченко. «Однопоточность: назад в будущее?». Перегрузка (97).
  13. ^ а б Эдвард Ли (10 января 2006 г.). «Проблема с нитями». Калифорнийский университет в Беркли.
  14. ^ «Многопоточность на уровне бизнес-логики считается вредной». ACCU.
  15. ^ Заяц без ошибок. «Операционные затраты в тактовых циклах ЦП».

дальнейшее чтение

  • Дэвид Р. Бутенхоф: Программирование с использованием потоков POSIX, Эддисон-Уэсли, ISBN  0-201-63392-2
  • Брэдфорд Николс, Дик Батлар, Жаклин Пру Фарелл: Программирование потоков Pthreads, O'Reilly & Associates, ISBN  1-56592-115-1
  • Пол Хайд: Программирование потоков Java, Самс, ISBN  0-672-31585-8
  • Джим Беверидж, Роберт Винер: Многопоточные приложения в Win32, Эддисон-Уэсли, ISBN  0-201-44234-5
  • Уреш Вахалия: Внутреннее устройство Unix: новые рубежи, Прентис Холл, ISBN  0-13-101908-2