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

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

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

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

Реализация потоков и процессов различается в разных операционных системах. [2] [ нужна страница ]

История

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

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

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

Процессы

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

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

Потоки ядра

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

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

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

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

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

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

Волокна

Волокна — это еще более легкая единица планирования, которая кооперативно планируется : работающее волокно должно явно « уступить », чтобы разрешить запуститься другому волокну, что делает их реализацию намного проще, чем потоки ядра или пользователя. Волокно может быть запланировано для запуска в любом потоке в том же процессе. Это позволяет приложениям получать улучшения производительности, управляя планированием самостоятельно, вместо того, чтобы полагаться на планировщик ядра (который может быть не настроен для приложения). Некоторые исследовательские реализации модели параллельного программирования OpenMP реализуют свои задачи через волокна. [7] [8] Тесно связаны с волокнами сопрограммы , с той разницей, что сопрограммы являются конструкцией уровня языка, в то время как волокна являются конструкцией уровня системы.

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

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

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

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

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

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

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

Упреждающее и кооперативное планирование

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

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

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

Системы с одним процессором обычно реализуют многопоточность с помощью квантования времени : центральный процессор (ЦП) переключается между различными программными потоками . Это переключение контекста обычно происходит достаточно часто, чтобы пользователи воспринимали потоки или задачи как работающие параллельно (для популярных серверных/настольных операционных систем максимальный квант времени потока, когда другие потоки ждут, часто ограничен 100–200 мс). В многопроцессорной или многоядерной системе несколько потоков могут выполняться параллельно , при этом каждый процессор или ядро ​​одновременно выполняет отдельный поток; на процессоре или ядре с аппаратными потоками отдельные программные потоки также могут выполняться одновременно отдельными аппаратными потоками.

Модели резьбы

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

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

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

Модель M :1 подразумевает, что все потоки уровня приложения отображаются в одну запланированную сущность уровня ядра; [9] ядро ​​не имеет сведений о потоках приложения. При таком подходе переключение контекста может быть выполнено очень быстро и, кроме того, его можно реализовать даже на простых ядрах, которые не поддерживают потоки. Однако одним из основных недостатков является то, что он не может воспользоваться аппаратным ускорением на многопоточных процессорах или многопроцессорных компьютерах: никогда не планируется более одного потока одновременно. [9] Например: если одному из потоков необходимо выполнить запрос ввода-вывода, весь процесс блокируется, и преимущество потоков не может быть использовано. GNU Portable Threads использует потоки на уровне пользователя, как и State Threads .

М:Н(гибридная резьба)

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

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

  • Активации планировщика, используемые в старых версиях реализации библиотеки потоков NetBSD POSIX ( модель M : N в отличие от модели реализации ядра или пространства пользователя 1:1)
  • Легковесные процессы, используемые в старых версиях операционной системы Solaris
  • Марсель из проекта PM2 .
  • Операционная система для Tera- Cray MTA-2
  • Компилятор 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. [10] FreeBSD 5 реализовала модель M:N. FreeBSD 6 поддерживала как 1:1, так и M:N, пользователи могли выбирать, какой из них следует использовать с данной программой, используя /etc/libmap.conf. Начиная с FreeBSD 7, 1:1 стал моделью по умолчанию. FreeBSD 8 больше не поддерживает модель M:N.

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

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

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

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

Синхронизация потоков и данных

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

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

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

Пулы потоков

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

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

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

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

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

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

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

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

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

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

Ссылки

  1. ^ Лампорт, Лесли (сентябрь 1979 г.). «Как создать многопроцессорный компьютер, который правильно выполняет многопроцессорные программы» (PDF) . IEEE Transactions on Computers . C-28 (9): 690–691. doi :10.1109/tc.1979.1675439. S2CID  5679366.
  2. ^ Таненбаум, Эндрю С. (1992). Современные операционные системы . Prentice-Hall International Editions. ISBN 0-13-595752-4.
  3. ^ Saltzer, Jerome Howard (июль 1966 г.). Управление трафиком в мультиплексной компьютерной системе (PDF) (диссертация доктора наук). стр. 20.
  4. ^ Саттер, Херб (март 2005 г.). «Бесплатный обед закончился: фундаментальный поворот к параллелизму в программном обеспечении». Журнал доктора Добба . 30 (3).
  5. ^ «Erlang: 3.1 Процессы».
  6. ^ Игнатченко, Сергей. Восемь способов обработки неблокируемых возвратов в программах передачи сообщений: от C++98 через C++11 к C++20. CPPCON. Архивировано из оригинала 2020-11-25 . Получено 2020-11-24 .{{cite AV media}}: CS1 maint: бот: исходный статус URL неизвестен ( ссылка )
  7. ^ Фера, Мануэль; Перейра, Ромен; Руссель, Адриен; Каррибо, Патрик; Штеффенель, Луис-Анджело; Готье, Тьерри (сентябрь 2022 г.). «Улучшение приложений на основе задач MPI+OpenMP для гетерогенных архитектур с поддержкой GPU» (PDF) . OpenMP в современном мире: от поддержки нескольких устройств до метапрограммирования . IWOMP 2022: 18-й международный семинар по OpenMP. Конспект лекций по информатике. Том 13527. стр. 3–16. doi :10.1007/978-3-031-15922-0_1. ISBN 978-3-031-15921-3. S2CID  251692327.
  8. ^ Ивасаки, Синтаро; Амер, Абдельхалим; Таура, Кэндзиро; Со, Сангмин; Баладжи, Паван. BOLT: Оптимизация параллельных регионов OpenMP с помощью потоков на уровне пользователя (PDF) . 28-я международная конференция по параллельным архитектурам и методам компиляции.
  9. ^ abcd Silberschatz, Abraham ; Galvin, Peter Baer; Gagne, Greg (2013). Концепции операционной системы (9-е изд.). Hoboken, NJ: Wiley. стр. 170–171. ISBN 9781118063330.
  10. ^ «Многопоточность в операционной среде Solaris» (PDF) . 2002. Архивировано из оригинала (PDF) 26 февраля 2009 г.
  11. ^ Менендес, Рауль; Лоу, Дуг (2001). CICS Мураха для программистов на COBOL. Mike Murach & Associates. стр. 512. ISBN 978-1-890774-09-7.
  12. ^ О'Херн, Питер Уильям; Теннент, РД (1997). Языки, подобные АЛГОЛу. Том 2. Birkhäuser Verlag . стр. 157. ISBN 978-0-8176-3937-2.
  13. ^ Игнатченко, Сергей (август 2010). «Однопоточность: назад в будущее?». Перегрузка (97). ACCU : 16–19.
  14. ^ ab Ли, Эдвард (10 января 2006 г.). «Проблема с потоками». Калифорнийский университет в Беркли.
  15. ^ Игнатченко, Сергей (август 2015). «Многопоточность на уровне бизнес-логики считается вредной». Перегрузка (128). ACCU : 4–7.
  16. ^ 'No Bugs' Hare (12 сентября 2016 г.). «Эксплуатационные расходы в тактах ЦП».

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

  • Дэвид Р. Бутенхоф: Программирование с потоками POSIX , Addison-Wesley, ISBN 0-201-63392-2 
  • Брэдфорд Николс, Дик Баттлар, Жаклин Пру Фарелл: Программирование Pthreads , O'Reilly & Associates, ISBN 1-56592-115-1 
  • Пол Хайд: Программирование потоков Java , Sams, ISBN 0-672-31585-8 
  • Джим Беверидж, Роберт Винер: Многопоточные приложения в Win32 , Addison-Wesley, ISBN 0-201-44234-5 
  • Уреш Вахалия: Внутреннее устройство Unix: Новые рубежи , Prentice Hall, ISBN 0-13-101908-2 
Retrieved from "https://en.wikipedia.org/w/index.php?title=Thread_(computing)&oldid=1246951389"