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

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

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

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

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

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

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

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

12 ответов


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


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

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

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

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

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

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

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

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

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

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

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], код и данные. И они оба сопоставлены со всем адресным пространством 2GB (линейным, пользовательским). Base=0, Limit=2GB. Они бы сделали один, но x86 не позволяет сегменту одновременно читать/писать и выполнять. Поэтому они сделали два и установили CS, чтобы указать на дескриптор кода, а остальные (DS, ES, SS и т. д.) - На другой [2]. Но оба указывают на одно и то же!

человек, интервьюирующий вас, сделал скрытое предположение, что он/она не заявил, и это глупый трюк.

что касается

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

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

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


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

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


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


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


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

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

           Process   Thread

   Stack   private   private
   Data    private   shared
   Code    private1  shared2

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


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

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

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


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

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

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

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


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


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

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

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


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


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

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