Можно ли / безопасно удалить класс, содержащий запущенные потоки, когда я хочу, чтобы потоки завершились?

Вот краткий пример:

class worker
{
    std::thread thread1;
    std::thread thread2;

    worker(){}

    start()
    {
        thread1 = std::thread([]()
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(50000));
        });
        thread1.deteach();

        thread2 = std::thread([]()
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(50000));
        });
        thread2.deteach();
    }

    ~worker()
    {
        // Ignore this part! - as per Richard's comment :)
        //thread1.join();   // <-- do I need this at all?
        //thread2.join();   // <-- do I need this at all?
    }
}

int main()
{
    worker *p_worker = new worker();
    p_worker->start();
    std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 1 sec

    delete p_worker;
}
  • Создайте работника
  • Запустите потоки, которые длятся 50 секунд
  • Через 1 секунду удалите воркера (вызывает деструктор)
  • В рабочем деструкторе я повторно присоединяюсь к потокам (возможно, сначала нужно проверить, могут ли они присоединиться?) - не совсем уверен, что мне нужно это сделать.
  • Затем рабочий уничтожается

Я посмотрел на этот вопрос: как-сделать-я-завершить-поток-в-c11, который предполагает, что нет переносимого способа c11 для завершения потоков.

Вопросов:

  • Полностью ли разрушены нити (не осталось мусора / протечек)?
    • Если «да», мне нужно повторно присоединиться к потокам, чтобы они были уничтожены? EDIT - Richard pointed out this is N/A
  • Это разумный подход?

Вы не можете присоединиться к отдельной цепочке

Richard Critten 11.04.2018 11:35

@RichardCritten ах, верно - я обновлю Q с учетом этого, спасибо :)

code_fodder 11.04.2018 11:36

Обычно, если класс «владеет» потоками, вы не отключаете их, сигнализируйте им каким-то образом о завершении в деструкторе и присоединении к ним.

Matteo Italia 11.04.2018 11:40

«Разумный ли это подход» к чему? Ваши потоки в данный момент просто спят, так что это нормально; но когда вы начинаете что-то делать с ними, если потоки используют какие-либо глобальные ресурсы, это, вероятно, не в порядке. Если ваши потоки делают что-то интенсивное для ЦП; тогда это, вероятно, тоже не нормально, так как вы хотите, чтобы они остановились, а не работали в течение 50 секунд над чем-то, что нельзя использовать.

UKMonkey 11.04.2018 11:41

@MatteoItalia мм .. хороший момент - я был убежден, что мне нужно отсоединить их, чтобы позволить main продолжить работу. Но я думаю, что меня это смутило, что я не присоединился к ним, спасибо :)

code_fodder 11.04.2018 11:51

@UKMonkey Я думаю, ваш комментарий отвечает на то, что мне нужно знать. В моем реальном коде я использовал мьютекс, чтобы «сигнализировать», когда поток простаивает, поэтому я был бы счастлив просто уничтожить worker ...

code_fodder 11.04.2018 11:52

@RichardCritten, пожалуйста, добавьте в качестве частичного ответа - я помечу его.

code_fodder 11.04.2018 11:53

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

code_fodder 11.04.2018 11:53

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

code_fodder 11.04.2018 11:53
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
9
185
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Да, потоки полностью уничтожаются dtor std::thread, если они все еще могут быть присоединены (запущены и не отсоединены).

Однако это не хорошие новости, так как будет называться std::terminate(), убивающий весь процесс.

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

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

code_fodder 11.04.2018 11:59

Все это верная информация, но, вероятно, ее следует немного уточнить для OP; бит «если они все еще могут быть присоединены» означает «если они не отсоединены и все еще работают». Итак, все это означает, что * если вы не присоединитесь к неотключенному потоку, ваша программа будет убита »; правильный курс действий здесь - присоединиться до того, как std::thread будет уничтожен.

Matteo Italia 11.04.2018 12:03

@MatteoItalia Итак, если потоки объединены в деструкторе worker (как у меня изначально, но без отсоединения) - тогда этот подход может сработать? - т.е. std :: terminate () не будет вызываться?

code_fodder 11.04.2018 12:10

Да. Отсоединение предназначено для запуска независимых потоков, которые могут запускаться сами по себе (и, возможно, присоединяться к ним другими способами). Если у вас есть владелец потока, обычно вы хотите присоединиться к нему после его удаления.

Matteo Italia 11.04.2018 12:14
Ответ принят как подходящий

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

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

Например, вы можете сделать что-то вроде этого:

class worker
{
private:
    std::thread thread1;
    std::atomic<bool> thread1ShouldRun;
    std::thread thread2;
    std::atomic<bool> thread2ShouldRun;

    void workerFunc1() {
        bool threadWorkIsDone = false;
        while (thread1ShouldRun.load()) {
            // Do Stuff
            // Set threadXShouldRun to false when you're done
            // thread1ShouldRun.store(false);
        }
    }

    void workerFunc2() {
        bool threadWorkIsDone = false;
        while (thread2ShouldRun.load()) {
            // Do Stuff
            // Set threadXShouldRun to false when you're done
            // thread2ShouldRun.store(false);
        }
    }

public:
    worker() {}

    void start()
    {
        thread1ShouldRun.store(true);
        thread1 = std::thread(&worker::workerFunc1, this);
        thread2ShouldRun.store(true);
        thread2 = std::thread(&worker::workerFunc2, this);            
    }

    ~worker()
    {
        thread1ShouldRun.store(false);
        // Protection in case you create a worker that you delete and never call start()
        if (thread1.joinable())
            thread1.join();
        thread2ShouldRun.store(false);
        if (thread2.joinable())
            thread2.join();
    }
};

int main()
{
    worker *p_worker = new worker();
    p_worker->start();
    std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // 1 sec

    delete p_worker; // Threads will be joined here
}

Мне нравится использование атома для этого :)

code_fodder 11.04.2018 13:32

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