TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.36K subscribers
Post #1141 3.29K
​​2 способа остановки воркеров
#опытным

Более менее всех опытные плюсовики знают классический подход к graceful остановке воркера. Это атомарный флаг, цикл внутри рабочей функции с проверкой и деструктор с установкой флага. Выглядит все примерно так:

class Worker {
public:
Worker() : t([this] {
while (!stop_flag.load(std::memory_order_relaxed)) {
std::cout << "Working\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << "Stopped\n";
}) {}
~Worker() {
stop();
}
void stop() {
stop_flag.store(true, std::memory_order_relaxed);
if (t.joinable()) {
t.join();
}
}
private:
std::atomic<bool> stop_flag = false;
std::thread t;
};


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

Важно, что есть тред и есть отдельная атомарная переменная, сигнализирующая об останове.

Но мы(и С++) выросли и появился новый инструмент останова воркера - std::jthread + std::stop_token.

Да. std::jthread - это не просто тред, который джойнится в деструкторе. Это тред с вшитой функциональностью остановки.

В отличие от std::thread, jthread содержит внутреннее приватное поле типа std::stop_source, которое хранит разделяемое состояние остановки потока. Из этого stop_source можно создать токены std::stop_token, через которые можно мониторить, остановится поток или нет. Грубо говоря, std::stop_source это ручка, за которую можно дернуть и перевести все ассоциированые с ней токены в состояние "остановка запрошена".

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

class Worker {
public:
Worker() : t([this](std::stop_token st) {
while (!st.stop_requested()) {
// полезная работа...
std::cout << "Working\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << "Stopped cleanly\n";
}) {}

// Деструктор автоматически вызовет request_stop() и join()
private:
std::jthread t;
};


Конструктор jthread принимает функцию, первым аргументом которой является std::stop_token; этот токен будет передан объектом jthread из его внутреннего std::stop_source. Это позволяет функции проверять во время выполнения, был ли запрошен останов, и завершаться, если запрос поступил.

Ручка std::stop_source дергается в момент вызова деструктора соответствующего jthread'а и сигнализирует всем токенам, что останов запрошен.

То есть начиная с С++20 механизм останова полностью встроен внутрь самого объекта и никаких дополнительных сущностей вводить не нужно.

Evolve. Stay cool.

#cpp20 #concurrency
  • 🔥 14
  • ❤ 7
  • 👍 5
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 →