Использовать обещание несколько раз

Я пытаюсь сигнализировать функции в отдельном потоке, используя std::promise

class MyClass {
  std::promise<void> exitSignal;
  std::thread monitorThread;
}

void MyClass::start() {
  exitSignal = std::promise<void>();
  std::future<void> futureObj = exitSignal.get_future();
  monitorThread = std::thread(&MyClass::monitorFunction, this, std::move(futureObj));
}

void MyClass::stop() {
  exitSignal.set_value();
  if (monitorThread.joinable()) {
    monitorThread.join();
  }
}

void MyClass::monitorFunction(std::future<void> futureObj) {
  while (futureObj.wait_for(std::chrono::seconds(1)) == std::future_status::timeout) {
      // do stuff
  }
}

Он работает хорошо, пока я не попытаюсь вызвать start во второй раз. Затем я получаю сообщение об ошибке

std::future_error: Promise already satisfied

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

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

molbdnilo 21.11.2022 11:47

Из cppreference: обратите внимание, что объект std::promise предназначен для использования только один раз.

Adrian Mole 21.11.2022 11:55

Я не могу воспроизвести вашу ошибку. Ваш код выглядит правильно (@AdrianMole, обратите внимание, что обещание заменено на start())

Homer512 21.11.2022 12:06

Вы вызываете start и stop из разных потоков? Может ли stop вызываться несколько раз из разных потоков?

Homer512 21.11.2022 12:10
Шаблоны Angular PrimeNg
Шаблоны Angular PrimeNg
Как привнести проверку типов в наши шаблоны Angular, использующие компоненты библиотеки PrimeNg, и настроить их отображение с помощью встроенной...
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Создайте ползком, похожим на звездные войны, с помощью CSS и Javascript
Если вы веб-разработчик (или хотите им стать), то вы наверняка гик и вам нравятся "Звездные войны". А как бы вы хотели, чтобы фоном для вашего...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Начала с розового дизайна
Начала с розового дизайна
Pink Design - это система дизайна Appwrite с открытым исходным кодом для создания последовательных и многократно используемых пользовательских...
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
14 Задание: Типы данных и структуры данных Python для DevOps
14 Задание: Типы данных и структуры данных Python для DevOps
проверить тип данных используемой переменной, мы можем просто написать: your_variable=100
2
4
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я собираюсь повторить комментарий @ Homer512 и предложить вам вызвать stop() дважды. Я сделал небольшой тест, используя ваш код:

#include <future>
#include <thread>
#include <iostream>
#include <chrono>

struct MyClass
{
    std::promise<void> exitSignal;
    std::thread monitorThread;

    void start();
    void stop();
    void monitorFunction(std::future<void> futureObj);
};

void MyClass::start()
{
    exitSignal = std::promise<void>();
    std::future<void> futureObj = exitSignal.get_future();
    monitorThread = std::thread(&MyClass::monitorFunction, this, std::move(futureObj));
}

void MyClass::stop()
{
    exitSignal.set_value();
    if (monitorThread.joinable())
    {
        monitorThread.join();
    }
}

void MyClass::monitorFunction(std::future<void> futureObj)
{
    while (futureObj.wait_for(std::chrono::seconds(1)) == std::future_status::timeout)
    {
        std::cout << "Bla\n";
    }
}

int main()
{
    MyClass myc;
    std::cout << "Start 1\n";
    myc.start();
    std::this_thread::sleep_for(std::chrono::seconds(3));
    std::cout << "Stop 1\n";
    myc.stop();
//    myc.stop(); // <- Boom!

    std::cout << "Wait\n";
    std::this_thread::sleep_for(std::chrono::seconds(3));

    std::cout << "Start 2\n";
    myc.start();
    std::this_thread::sleep_for(std::chrono::seconds(3));
    std::cout << "Stop 2\n";
    myc.stop();
}

Когда я запускаю это как есть (второй stop закомментирован), он работает без проблем:

Start 1
Bla
Bla
Stop 1
Wait
Start 2
Bla
Bla
Stop 2

Но если вставляется второй stop, то он попадает в исключение:

terminate called after throwing an instance of 'std::future_error'
  what():  std::future_error: Promise already satisfied
Aborted

Очень хорошо выведено! Это действительно второй вызов остановки из другого потока. Спасибо!

Frank 21.11.2022 13:45

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