TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.36K subscribers
Post #1088 3.36K
​​Процесс и поток. Поток
#новичкам

Чтобы ввести термин "поток" надо очень верхнеуровнего понять, как вообще код исполняется на ядре.

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

CPU нужны операнды и инструкция, что с ними делать.

Начнем с инструкций

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

Машинный код программы хранится в памяти процесса и для него нужен какой-то механизм исполнения.

Чтобы отслеживать, какая инструкция будет выполняться следующей, нужен специальный Program Counter(PC) или счетчик инструкций. Процесс такой: CPU загружает инструкцию, на которую указывает PC, увеличивает счетчик, декодирует инструкцию, делает нужные преобразования над операндами, сохраняет результат и цикл повторяется снова.

Теперь операнды

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

Из какой?

Из 3-х областей памяти: стека, кучи и сегмента глобальных данных. Куча и глобальные данные шарятся между потоками исполнения и принадлежат процессу.

А вот как раз стек и связан с непосредственным обеспечением исполнения кода в моменте. Он нужен для работы функций. Каждый фрейм стека соответствует одной вызванной, но ещё не завершённой функции. Как только в коде вызывается функция, на стек кладется информация о ней. В основном это локальные переменные и адрес возврата. Так информация об исполнении всех вызванных в данный момент функциях остается в памяти.

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

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

Вот это очень грубо то, как исполняется код на процессорах.

Но этот процесс описывает исполнение одной программы. А в современных компьютерах есть многозадачность аля множество программ могут выполняться на одном ядре. Как этого достигают?

На самом деле стек, значения счетчика инструкций и регистров полностью определяют состояние исполнения текущего кода. Оно называется контекстом. Если где-то сохранить это состояние, то можно загрузить PС и регистры из другого контекста и продолжить исполнение уже другой программы, а исполнение изначальной прервется. Потом, когда наступит нужный момент, исполнение изначальной программы продолжится также с помощью загрузки ее сохраненного состояния.

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

Поток в программе может быть один и может быть несколько.

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

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

Ну и совсем коротко о том, как явно в программе создать поток.

В С++ это делается через объект std::thread.

void hello() {
std::cout << "Hello thread!\n";
}

int main() {
std::thread t(hello);
t.join();
}


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

Share resources. Stay cool.

#OS #concurrency
  • 🔥 21
  • ❤ 11
  • 👍 10
  • 😁 4
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →