0

Code

#include <iostream> #include <thread> #include <atomic> #include <future> void listenForInput(std::promise<bool>&& interruptPromise) { std::cin.get(); std::atomic_thread_fence(std::memory_order_acquire); interruptPromise.set_value(true); std::cout << "[Speech 100] no u \n"; } bool is_ready(std::future<bool> const& f) { return f.wait_for(std::chrono::seconds(0)) == std::future_status::ready; } int main() { std::atomic_thread_fence(std::memory_order_acquire); std::promise<bool> interruptPromise; //interuptPromise.set_value(false); /* Commenting line above makes program work. Uncommenting results in while loop below not being executed */ std::atomic_thread_fence(std::memory_order_release); std::future<bool> interruptFuture = interuptPromise.get_future(); std::thread reply(listenForInput, std::move(interruptPromise)); while (!is_ready(interruptFuture)) { std::cout << "Your mother was a hamster, " "and your father smelt of elderberries " "(Press any key to reply)\n"; std::this_thread::sleep_for( std::chrono::seconds(2) ); } reply.join(); std::cin.get(); return 0; } 

Context

In the code above in the main thread the same line of text is constantly being displayed until it's interrupted from the other thread. The interrupt occurs after any input from the user. The message of user making an input is being delivered to the main thread via std::promise and std::future. is_ready is an utilitarian function used for checking whether promise was satisfied.

My interest lays in the third line of the main() function and what's around it. At first I tried to set value of interruptPromise in advance to false (which would indicate that interrupt didn't occur so that later in other thread I'd change it to true to indicate that it did occur). It resulted in interruptPromise being satisfied before while loop even started thus the loop not being executed.

Questions

  1. I get that std::promise becomes satisfied when set_value is called. But how do I assign a value in advance and then make std::future react to it being changed (for instance future would react to false bool being changed to true)?
  2. Would I ever need to do such a thing?
  3. Does std::promise has default values for certain types (if it needs such at all)?
2
  • 1
    From std::promise "Note that the std::promise object is meant to be used only once." Commented Apr 5, 2021 at 10:28
  • 1
    It's unclear what you're trying to achieve with your program though it sounds like you need a queue instead of a promise.. BTW, you don't need any atomic_thread_fence in this example, the promise already takes care of memory ordering (that is also explained in documentation). Commented Apr 5, 2021 at 11:23

1 Answer 1

1

Primise/future isn't a value that changes, it is a value that is delivered later.

If you want a value that changes, you can stich together one out of a mutex, condition variable and a bool. However, reasoning about a bool that changes more than once in a multithreaded environment will break most people's brains in my experience.

Better options are things like queues of data guarded by the above, and try pop or try pop all methods that get data off the queue if it is there.

template<class T> struct threadsafe_queue{ std::optional<T> try_pop(); std::optional<T> wait_and_pop(); bool is_aborted() const; std::deque<T> pop_all(); void push(T); void abort(); private: std::condition_variable cv; mutable std::mutex m; std::deque<T> queue; bool isAborted=false; std::unique_lock<std::mutex> lock() const; }; 

write the above, then send the user input via the queue. The main thread does a try pop and processes if it gets any.

std::optional<T> try_pop(){ auto l=lock(); if (is_aborted()||queue.empty()) return {}; auto r=queue.front(); queue.pop_front(); return r; } std::optional<T> wait_and_pop(){ auto l=lock(); cv.wait(l, [&]{return is_aborted()||!queue.empty();}); if (is_aborted()) return {}; auto r=queue.front(); queue.pop_front(); return r; } void push(T t){ auto l=lock(); if (is_aborted()) return; queue.push_back(std::move(t)); cv.notify_one(); } void abort(){ auto l=lock(); isAborted=true; cv.notify_all(); } 

there are some sample implementations.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.