Что такое стек задачи и для чего он используется? - ОК / ОС-II

Итак, я читаю из книги MicroC/OS-II, но в разделе, посвященном стекам задач, я не смог точно определить, что такое стек, и, самое главное, для чего он используется. Я знаю, что это не что-то длинное и сложное, но я вроде как должен это понять. Книга только говорит о том, как установить размер стека и некоторые другие вещи, как это. Итак, кто-нибудь может объяснить мне короткими и простыми словами, что такое стек задач и для чего он используется в uC/OS-II?

4 ответа

Решение

В общем случае в контексте процедурного языка программирования в стеке хранятся локальные переменные функции / процедуры / подпрограммы и адрес возврата (в "кадре стека") - чем больше глубина вызова, тем больше кадров стека сохранено - по одному для каждой функции, которая еще не вернулась. Эта часть справедлива независимо от того, используете ли вы ОСРВ, такую ​​как MicroC/OS-II, или нет.

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

Многие процессоры имеют указатель стека, и большинство из них имеют инструкции, которые специально используют этот указатель стека. Указатель стека - это регистр, который содержит адрес, в отличие от счетчика программы. Стек - это просто память, на которую указывает указатель стека. На более высоком уровне вы или операционная система или кто-то делит доступное пространство памяти для различных целей, немного для данных, немного для программы, немного для кучи (mallocs и освобождает) а некоторые для стека. Указатель стека и соответствующие инструкции позволяют коду временно выделить некоторую память. Например, глобальная переменная предназначена по крайней мере на весь период жизни вашей программы, находящейся в одном месте памяти. Локальной переменной требуется только место в памяти во время выполнения функции, когда функция возвращает, вам не нужна эта локальная переменная память (статически определенные локальные переменные выделяются как глобальные, но доступны только во время этой функции, поэтому не являются временными). Вы можете сделать malloc и free в функции для выделения этой локальной памяти, или вы можете просто использовать стек. И многие / большинство компиляторов просто используют стек. В дополнение к локальным переменным вам может потребоваться сохранить адрес возврата, если функция a() вызывает функцию b(), чтобы перейти от b к тому месту, где вы находились, вам необходимо вернуться к следующей инструкции после вызова b()., если B вызывает c, то в контексте b() вам нужно сохранить возврат в a(), а теперь в c() вам нужно знать, как вернуться к b(). И так далее. Это зависит от архитектуры и соглашения о вызовах, некоторые архитектуры всегда используют стек для возвратов, другие склоняются к использованию определенного регистра. При вложении вызовов, хотя все архитектуры должны будут в конечном итоге использовать стек для адреса возврата, поэтому здесь также используется стек. Если функция a() вызывает себя 10 раз и имеет одно локальное целое число, а обратный адрес, скажем, требует 8 байтов стека на вызов, то первый вызов перемещает указатель стека на 8 байтов, выделяя 8 байтов, второй вызывает еще 8 байтов и т. Д., когда вы начинаете нажимать на return, указатель стека перемещается назад на 8 байтов, другой возвращает еще 8 байтов назад на указатель стека.

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

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

Я не знаю MicroC/OS-II, но стек задач почти всегда одинаков:
Во время выполнения задачи он хранит данные, которые требуются в текущем контексте. Это означает, что когда вызывается подпрограмма (метод и т. Д.), Поверх стека сохраняется "кадр стека". В этом стековом кадре хранятся локальные переменные вызываемой подпрограммы, адрес возврата, используемый при завершении подпрограммы, и некоторая другая информация. Когда подпрограмма возвращается, кадр стека удаляется. Если подпрограмма вызывает другую (или сама рекурсивно), другой кадр стека сохраняется поверх текущего.
В отличие от стека, в котором сохраненные данные удаляются в обратном порядке по мере их сохранения, куча хранит данные до тех пор, пока их память не освобождается, что можно сделать в произвольном порядке.

Стек - это структура данных типа "последний пришел - первым вышел" (LIFO), которая используется процедурными языками для выполнения локальной переменной push / pop, регистров ЦП, адресов возврата перед вызовом функции или при возникновении прерывания или для подготовки переключений контекста.

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

Стек может расти вверх или вниз в памяти. Это то, что будет зависеть от микроконтроллера.

Кроме того, многие микроконтроллеры имеют несколько стеков. 1) стек пользователя 2) стек исключений или стек прерываний

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

Стек исключений или стек прерываний является общим для всей системы.

Другие вопросы по тегам