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

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

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

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

Мой ответ: yep (подумал, что это легко) Stack, Data, Code, Heap

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

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

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

Ответы

Ответ 1

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

Ответ 2

Из Wikipedia (я думаю, что это сделало бы действительно хороший ответ для интервьюера: P)

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

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

Ответ 3

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

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

У нас есть следующее из раздела 2.2.2 Модель классической резьбы в современных операционных системах 3e от Tanenbaum:

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

Он продолжает:

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

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

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        |

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

Ответ 4

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

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

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

Так что в отношении

Q. Так скажите мне, какой сегментный поток поделиться?

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

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


  • По крайней мере, для пользовательского пространства.
  • От ntsd notepad: cs=001b ss=0023 ds=0023 es=0023

Ответ 5

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

Ответ 6

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

Ответ 7

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

Ответ 8

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

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

           Process   Thread

   Stack   private   private
   Data    private   shared
   Code    private1  shared2

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

Ответ 9

Темы разделяют все [1]. Для всего процесса есть одно адресное пространство.

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

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


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

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

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

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


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

Ответ 10

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

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

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

Ответ 11

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

Ответ 12

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

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

Ответ 13

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

  • идентификатор процесса и идентификатор родительского процесса;
  • идентификатор группы процессов и идентификатор сеанса;
  • управляющий терминал;
  • учетные данные процесса (идентификаторы пользователей и групп);
  • дескрипторы открытых файлов;
  • блокировки записей, созданные с помощью fcntl();
  • расположение сигналов;
  • информация, связанная с файловой системой: umask, текущий рабочий каталог и корневой каталог;
  • интервальные таймеры (setitimer()) и POSIX-таймеры (timer_create());
  • Значения System V семафора отменить (semadj) (раздел 47.8);
  • ограничения ресурсов;
  • Время процессора потребляется (как возвращается times());
  • потребляемые ресурсы (как возвращено getrusage()); а также
  • хорошее значение (устанавливается setpriority() и nice()).

Среди атрибутов, которые различны для каждого потока, следующие:

  • идентификатор потока (раздел 29.5);
  • сигнальная маска;
  • специфичные для потока данные (раздел 31.3);
  • стек альтернативных сигналов (sigaltstack());
  • переменная errno;
  • среда с плавающей точкой (см. fenv(3));
  • политика и приоритет планирования в реальном времени (разделы 35.2 и 35.3);
  • Сродство к процессору (специфично для Linux, описано в разделе 35.4);
  • возможности (специфичные для Linux, описаны в главе 39); а также
  • стек (локальные переменные и информация о связи между вызовами функций).

Отрывок из: Интерфейс программирования Linux: Справочник по системному программированию Linux и UNIX, Майкл Керриск, стр. 619