Я пытаюсь сигнализировать функции в отдельном потоке, используя 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
Как так? Я обновляю обещание каждый раз, когда начинаю, и будущее кажется реальным...
Из cppreference: обратите внимание, что объект std::promise предназначен для использования только один раз.
Я не могу воспроизвести вашу ошибку. Ваш код выглядит правильно (@AdrianMole, обратите внимание, что обещание заменено на start()
)
Вы вызываете start и stop из разных потоков? Может ли stop вызываться несколько раз из разных потоков?
Я собираюсь повторить комментарий @ 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
Очень хорошо выведено! Это действительно второй вызов остановки из другого потока. Спасибо!
Пожалуйста, опубликуйте минимальный воспроизводимый пример.