Ответ
Нет, поток в C++ (и в общем случае) не может «перезапустить» себя в прямом смысле. Объект std::thread представляет собой единичный поток выполнения. Как только функция потока завершается (возвращает управление или выбрасывает исключение), поток завершает свою работу и переходит в состояние not joinable. Повторно использовать этот же объект std::thread для запуска новой функции нельзя — это вызовет исключение std::system_error.
Что можно сделать:
- Завершить текущий поток и создать новый с той же логикой. Это не перезапуск, а создание нового потока.
- Использовать цикл внутри функции потока, чтобы он не завершался, а ждал новых задач. Это классический подход для worker-потоков в пуле.
Пример 1: Ошибочная попытка «переиспользования»:
#include <thread>
#include <iostream>
void task() {
std::cout << "Task done.n";
}
int main() {
std::thread th(task);
th.join(); // Поток завершен
// Попытка запустить поток снова через тот же объект
th = std::thread(task); // ОШИБКА! Объект th после join() находится в невалидном состоянии.
// Правильно: нужно создать новый объект.
std::thread th2(task);
th2.join();
return 0;
}
Пример 2: Реализация worker-потока с циклом (более практичный подход):
#include <iostream>
#include <thread>
#include <atomic>
#include <queue>
#include <mutex>
#include <condition_variable>
class WorkerThread {
std::thread thread;
std::atomic<bool> running{true};
std::queue<std::function<void()>> tasks;
std::mutex queue_mutex;
std::condition_variable cv;
void loop() {
while (running) {
std::function<void()> task;
{
std::unique_lock lock(queue_mutex);
// Ждем, пока не появится задача или не придет сигнал на остановку
cv.wait(lock, [this]() { return !tasks.empty() || !running; });
if (!running && tasks.empty()) break;
task = std::move(tasks.front());
tasks.pop();
}
task(); // Выполняем задачу
}
std::cout << "Worker thread finished.n";
}
public:
WorkerThread() : thread(&WorkerThread::loop, this) {}
~WorkerThread() {
stop();
if (thread.joinable()) thread.join();
}
void stop() {
running = false;
cv.notify_all(); // Будим поток, чтобы он мог завершиться
}
void post_task(std::function<void()> task) {
{
std::lock_guard lock(queue_mutex);
tasks.push(std::move(task));
}
cv.notify_one(); // Сигнализируем потоку, что есть работа
}
};
В этом примере поток работает в цикле (loop()), обрабатывая множество задач, и завершается только по сигналу. Это эффективнее, чем постоянное создание и уничтожение потоков.