微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

需要帮助了解 std::promise 和 std::future 在这种情况下如何工作

如何解决需要帮助了解 std::promise 和 std::future 在这种情况下如何工作

代码

#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;
}

背景

在上面的代码中,主线程中的同一行文本不断显示,直到它被另一个线程中断。中断发生在用户的任何输入之后。用户进行输入的消息通过 std::promisestd::future 传递到主线程。 is_ready一个实用函数,用于检查 promise 是否得到满足。

我的兴趣在于 main() 函数的第三行及其周围的内容。起初,我试图将 interruptPromise 的值提前设置为 false(这表示中断没有发生,以便稍后在其他线程中将其更改为 true 以表明它确实发生了)。它导致 interruptPromisewhile 循环甚至开始之前得到满足,因此循环没有被执行。

问题

  1. 我知道调用 std::promiseset_value 会感到满意。但是我如何提前分配一个值,然后让 std::future 对它的更改做出反应(例如 future 会对 false bool 被更改为 {{1} })?
  2. 我需要做这样的事情吗?
  3. true 是否有某些类型的认值(如果它需要的话)?

解决方法

Primise/future 不是一个会改变的价值,而是一个稍后交付的价值。

如果你想要一个改变的值,你可以将互斥锁、条件变量和布尔值组合在一起。然而,根据我的经验,推理一个在多线程环境中改变不止一次的布尔值会打破大多数人的大脑。

更好的选择是像上面保护的数据队列,尝试 pop 或尝试弹出所有从队列中取出数据的方法(如果存在)。

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;
};

写上面,然后通过队列发送用户输入。主线程执行 try pop 并处理如果有任何结果。

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();
}

有一些示例实现。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。