Какие ресурсы разделяются между потоками?


недавно мне задали вопрос в интервью, в чем разница между процессом и потоком. Действительно, я не знал ответа. Я задумался на минуту и дал очень странный ответ.

потоки используют одну и ту же память, процессы-нет. Ответив на это, интервьюер злобно улыбнулся и засыпал меня следующими вопросами:

вопрос:вы знаете сегменты, в которых программа делится?

мой ответ: да (думал, что это было легко) стек, данные, код, куча

вопрос:Итак, скажите мне: какие сегменты разделяют потоки?

Я не мог ответить на это и в конечном итоге сказал все из них.

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

12 209

12 ответов:

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

с Википедия (Я думаю, что это будет действительно хороший ответ для интервьюера: P)

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

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

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

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

у нас есть следующее из раздела 2.2.2 Классическая Модель Потока на современный Операционные системы 3Э по Таненбаума:

модель процесса базируется на двух независимых концепциях: ресурс группировка и выполнение. Иногда полезно их разделить; вот где приходят потоки....

Он продолжил:

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

далее он предлагает следующую таблицу:

Per process items             | Per thread items
------------------------------|-----------------
Address space                 | Program counter
Global variables              | Registers
Open files                    | Stack
Child processes               | State
Pending alarms                |
Signals and signal handlers   |
Accounting information        |

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

скажите интервьюеру, что это полностью зависит от реализации ОС.

Возьмем, к примеру, Windows x86. Есть только 2 сегменты [1], код и данные. И они оба отображаются на все 2 ГБ (линейное, пользовательское) адресное пространство. Base=0, Limit=2GB. Они бы сделали один, но x86 не позволяет сегменту одновременно читать/писать и выполнять. Поэтому они сделали два и установили CS, чтобы указать на дескриптор кода, а остальные (DS, ES, SS и т. д.) указывают на другой [2]. Но оба указывают на одно и то же!

что касается

вопрос: Так скажите мне, какой сегмент нить поделиться?

сегменты не имеют отношения к вопросу, по крайней мере, в Windows. Потоки разделяют все адресное пространство. Существует только 1 сегмент стека, SS, и он указывает на тот же самый материал, что DS, ES и CS do [2]. То есть все чертово пространство пользователя. 0-2 ГБ. Конечно, это не означает, что потоки имеют только 1 стек. Естественно, каждый из них имеет свой собственный стек, но x86 сегменты не используются для этой цели.

может быть, * Никс делает что-то другое. Кто знает. Предпосылка, на которой был основан вопрос, была нарушена.


  1. по крайней мере для пространства пользователя.
  2. С ntsd notepad:cs=001b ss=0023 ds=0023 es=0023

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

процесс имеет сегменты кода, данных, кучи и стека. Теперь указатель инструкции (IP) потока или потоков указывает на сегмент кода процесса. Сегменты данных и кучи совместно используются всеми потоками. А как насчет области стека? Что на самом деле стек? Его область, созданная процессом только для его потока для использования... потому что стеки можно использовать гораздо быстрее, чем кучи и т. д. Область стека процесса разделена между потоками, т. е. если есть 3 темы, затем область стека процесса делится на 3 части и каждая отдается 3 потокам. Другими словами, когда мы говорим, что каждый поток имеет свой собственный стек, этот стек фактически является частью области стека процесса, выделенной каждому потоку. Когда поток завершает свое выполнение, стек потока восстанавливается процессом. Фактически, не только стек процесса разделен между потоками, но и весь набор регистров, которые использует поток, например регистры SP, PC и state, являются регистрами процесса. Поэтому, когда дело доходит до совместного использования, области кода, данных и кучи являются общими, а область стека просто разделена между потоками.

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

потоки совместно используют данные и код, а процессы-нет. Стек не является общим для обоих.

процессы также могут совместно использовать память, точнее код, например после Fork(), но это деталь реализации и (операционная система) оптимизация. Код, совместно используемый несколькими процессами, будет (надеюсь) дублироваться при первой записи в код - это известно как копировать на запись. Я не уверен в точной семантике кода потоков, но я предполагаю общий код.

           Process   Thread

   Stack   private   private
   Data    private   shared
   Code    private1  shared2

1 код логически частные, но могут быть разделены по соображениям производительности. 2 Я не уверен на 100%.

Threads share все [1]. Существует одно адресное пространство для всего процесса.

каждый поток имеет свой собственный стек и регистры, но стеки всех потоков отображаются на общее адресное пространство.

Если один поток выделяет некоторый объект в своем стеке и отправляет адрес другому потоку, они оба будут иметь равный доступ к этому объекту.


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

формат файла для исполняемого файла (например, ELF) имеет в нем отдельные разделы, которые могут называться сегментами, содержащими скомпилированный код (текст), инициализированные данные, символы компоновщика, отладочную информацию и т. д. Здесь нет сегментов кучи или стека, так как это конструкции только для времени выполнения.

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

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


[1] Хорошо, я знаю: сигнальные маски, TSS/TSD и т. д. Однако адресное пространство, включая все его сопоставленные сегменты программы, по-прежнему является общим.

в рамках x86 можно разделить столько сегментов (до 2^16-1). Сегмент/концы директив ASM позволяют это, а операторы SEG и OFFSET позволяют инициализировать регистры сегментов. CS: IP обычно инициализируются загрузчиком, но для DS, ES, SS приложение отвечает за инициализацию. Многие среды позволяют использовать так называемые" упрощенные определения сегментов".код. ,данные. ,ОНБ. ,стек и т. д. а также в зависимости от "модели памяти" (малые, большие, компактные и т. д.) загрузчик инициализирует сегментные регистры соответствующим образом. Обычно.данные. ,ОНБ. ,стек и другие обычные сегменты (я не делал этого с 20 лет, поэтому я не помню всех) сгруппированы в одну группу - именно поэтому обычно DS, ES и SS указывают на одну и ту же область, но это только для упрощения вещей.

В общем случае все сегментные регистры могут иметь разные значения во время выполнения. Итак, вопрос интервью был прав: какой из кода, данных и стека разделяется между потоками. Управление кучей-это что - то другое-это просто последовательность вызовов ОС. Но что делать, если у вас нет ОС вообще, как во встроенной системе - вы все еще можете иметь новый/удалить в своем коде?

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

поток разделяет кучу (есть исследование о потоке конкретной кучи), но текущая реализация разделяет кучу. (и конечно же код)

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

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