Потоки имеют две перспективы: операционные системы и языки программирования. В обоих случаях есть некоторые различия в атрибутах потока.
Минимальное определение потока - это то, что это происходит последовательно, одно за другим.
В типичной модели машинного исполнения каждый поток имеет свой собственный набор регистров общего назначения и свой собственный программный счетчик. Если машина устанавливает конкретный регистр в качестве указателя стека, существует одна копия на поток.
С точки зрения операционной системы, минимум, который операционная система должна сделать для поддержки потоков, - это способ переключения между ними. Это может происходить либо автоматически ( вытесняющая многозадачность, либо только когда поток делает явный запрос (кооперативная многозадачность; в этом случае потоки иногда называют волокнами ). Существуют также гибридные модели как с вытесняющим, так и с совместным выходом, например, вытеснение между потоками разных групп. или задачи, но явные уступки между потоками одной и той же группы / задачи. Переключение между потоками предполагает как минимум сохранение значений регистров старого потока и восстановление значений регистров нового потока.
В многозадачной операционной системе, которая обеспечивает изоляцию между задачами (или процессами , вы можете рассматривать эти термины как синонимы в контексте ОС), каждая задача имеет свои собственные ресурсы, в частности адресное пространство, но также и открытые файлы, привилегии и т. Д. Изоляция имеет быть предоставленным ядром операционной системы , сущностью, которая находится над процессами. У каждой задачи обычно есть по крайней мере один поток - задача, которая не выполняет код, не очень полезна. Операционная система может поддерживать или не поддерживать несколько потоков в одной задаче; например, оригинальный Unix этого не сделал. Задача все еще может запускать несколько потоков, организуя переключение между ними - для этого не требуется никаких специальных привилегий. Это называется « пользовательские темы»», Особенно в контексте Unix. В настоящее время большинство систем Unix предоставляют потоки ядра, в частности потому, что это единственный способ иметь несколько потоков одного и того же процесса на разных процессорах.
Большинство ресурсов операционной системы, кроме времени вычислений, привязаны к задачам, а не потокам. Некоторые операционные системы (например, Linux) явно разграничивают стеки, и в этом случае каждый поток имеет свой собственный; но есть операционные системы, в которых ядро ничего не знает о стеках, они всего лишь часть кучи, насколько это возможно. Ядро также обычно управляет контекстом ядра для каждого потока, который является структурой данных, содержащей информацию о том, что поток делает в настоящее время; это позволяет ядру обрабатывать несколько потоков, заблокированных в системном вызове одновременно.
Что касается операционной системы, то потоки задачи выполняют один и тот же код, но находятся в разных позициях в этом коде (разные значения счетчика программы). Может случиться или не случиться так, что определенные части кода программы всегда выполняются в определенных потоках, но обычно есть общий код (например, служебные функции), который может быть вызван из любого потока. Все потоки видят одни и те же данные, иначе они будут рассматриваться как разные задачи; если к некоторым данным может получить доступ только конкретный поток, это обычно относится исключительно к языку программирования, а не к операционной системе.
В большинстве языков программирования память распределяется между потоками одной и той же программы. Это модель параллельного программирования с общей памятью ; он очень популярен, но также подвержен ошибкам, потому что программист должен быть осторожен, когда одни и те же данные могут быть доступны нескольким потокам, поскольку могут возникнуть условия гонки . Обратите внимание, что даже локальные переменные могут совместно использоваться потоками: «локальная переменная» (обычно) означает переменную, имя которой допустимо только во время одного выполнения функции, но другой поток может получить указатель на эту переменную и получить к ней доступ.
Существуют также языки программирования, где каждый поток имеет свое собственное хранилище, и связь между ними происходит путем отправки сообщений по каналам связи. Это модель передачи сообщений параллельного программирования. Erlangявляется основным языком программирования, который фокусируется на передаче сообщений; его среда выполнения имеет очень легкую обработку потоков, и она поощряет программы, написанные со многими недолговечными потоками, в отличие от большинства других языков программирования, где создание потока является относительно дорогой операцией, а среда выполнения не может поддерживать очень большие количество потоков одновременно. Последовательное подмножество Эрланга (часть языка, которая происходит в потоке, в частности манипулирование данными) является (в основном) чисто функциональной; таким образом, поток может отправить сообщение другому потоку, содержащему некоторые данные, и ни одному из потоков не нужно беспокоиться о том, что данные будут изменены другим потоком во время его использования.
Некоторые языки смешивают две модели, предлагая локальное хранилище потоков с системой типов или без нее, чтобы отличать локальное хранилище потоков от глобальных. Локальное хранилище потоков - это, как правило, удобная функция, которая позволяет имени переменной обозначать разные места хранения в разных потоках.
Некоторые (сложные) наблюдения, которые могут быть интересны, чтобы понять, что такое потоки:
- Какой минимум требуется ядру для поддержки нескольких потоков?
- В многопроцессорной среде, что нужно для переноса потока с одного процессора на другой?
- Что потребуется для реализации совместной многопоточности ( сопрограммы ) на вашем любимом языке программирования без поддержки операционной системы и без использования встроенной поддержки, если таковая имеется? (Помните, что большинство языков программирования не имеют необходимых примитивов для реализации сопрограмм внутри одного потока.)
- Как мог бы выглядеть язык программирования, если бы он имел параллелизм, но не имел (явного) понятия потоков? (Главный пример: пи-исчисление .)