代码之家  ›  专栏  ›  技术社区  ›  Lingxi

为什么没有std::future::try\u wait()?

  •  1
  • Lingxi  · 技术社区  · 8 年前

    考虑到有 std::future::wait_for/until() ,我不明白为什么没有 std::future::try_wait() 。我目前正在编写一个生产者-消费者示例,我想使用 std::future 作为向使用者线程发送返回信号的便捷方式。我的消费者代码是

    void consume(std::future<void>& stop) {
      while (!stop.try_wait()) { // alas, no such method
        // try consuming an item in queue
      }
    }
    

    我想模拟一下 try_wait() 持续时间为零 wait_for() 这真的很难看。作为一个附带问题:是否有其他方便的方法来通知使用者线程返回?

    2 回复  |  直到 8 年前
        1
  •  1
  •   Yakk - Adam Nevraumont    8 年前

    std::experimental::future 有一个 .is_ready() .then( F ) 添加到其中的方法。

    is_ready 可能是你的 try_wait (无超时)。

    wait_for ,如上所述,为您提供了 try\u等待 在实践中。


    std::future 即使可以作为一种信号机制使用,也没有设计为一种信号机制。如果需要信令机制,请使用条件变量、互斥量和存储信号状态的状态(可能组合它们)创建一个。

    struct state {
      bool stop = false;
      unsigned some_value = 7;
      friend auto as_tie( state const& s ) {
        return std::tie(s.stop, s.some_value);
      }
      friend bool operator==( state const& lhs, state const& rhs ) {
        return as_tie(lhs)==as_tie(rhs);
      }
    };
    
    template<class State, class Cmp=std::equal<State>>
    struct condition_state {
      // gets a copy of the current state:
      State get_state() const {
        auto l = lock();
        return state;
      }
      // Returns a state that is different than in:
      State next_state(State const& in) const {
        auto l = lock();
        cv.wait( l, [&]{ return !Cmp{}(in, state); } );
        return state;
      }
      // runs f on the state if it changes from old.
      // does this atomically in a mutex, so be careful.
      template<class F>
      auto consume_state( F&& f, State old ) const {
        auto l = lock();
        cv.wait( l, [&]{ return !Cmp{}(old, state); } );
        return std::forward<F>(f)( state );
      }
      // runs f on the state if it changes:
      template<class F>
      auto consume_state( F&& f ) const {
        return consume_state( std::forward<F>(f), state );
      }
      // calls f on the state, then notifies everyone to check if
      // it has changed:
      template<class F>
      void change_state( F&& f ) {
        {
          auto l = lock();
          std::forward<F>(f)( state );
        }
        cv.notify_all();
      }
      // Sets the value of state to in
      void set_state( State in ) {
        change_state( [&](State& state) {
          state = std::move(in);
        } );
      }
    private:
      auto lock() const { return std::unique_lock<std::mutex>(m); }
      mutable std::mutex m;
      std::condition_variable cv;
      State state;
    };
    

    例如,假设 State 是一个准备好的任务的载体和一个说“中止”的布尔语:

    struct tasks_todo {
      std::deque< std::function<void()> > todo;
      bool abort = false;
      friend bool operator==()( tasks_todo const& lhs, tasks_todo const& rhs ) {
        if (lhs.abort != rhs.abort) return false;
        if (lhs.todo.size() != rhs.todo.size()) return false;
        return true;
      }
    };
    

    然后,我们可以按如下方式编写队列:

    struct task_queue {
      void add_task( std::function<void()> task ) {
        tasks.change_state( [&](auto& tasks) { tasks.todo.push_back(std::move(task)); } );
      }
      void shutdown() {
        tasks.change_state( [&](auto& tasks) { tasks.abort = true; } );
      }
      std::function<void()> pop_task() {
        return tasks.consume_state(
          [&](auto& tasks)->std::function<void()> {
            if (tasks.abort) return {};
            if (tasks.todo.empty()) return {}; // should be impossible
            auto r = tasks.front();
            tasks.pop_front();
            return r;
          },
          {} // non-aborted empty queue
        );
      }
    private:
      condition_state<task_todo> tasks;
    };
    

    或者类似的。

        2
  •  1
  •   seccpur    8 年前

    由于std::future::wait\u for不可用,可以指定自己的超时例程,如代码段所示:

    void even(int n,promise<bool> p)
    {
       this_thread::sleep_for(chrono::milliseconds(500ms)); //set milliseconds(10ms) to display result
       p.set_value( n%2 == 0?true:false);
    }
    
    
    int main()
    
    {
        promise<bool> p;
        future<bool> f =p.get_future();
        int n = 100;
        std::chrono::system_clock::time_point tp1 = std::chrono::system_clock::now() ;
        thread t([&](){ even(n,move(p)); });      
    
        auto span = std::chrono::milliseconds(200ms);
    
        std::future_status s;
    
        do
        {
            s =f.wait_for(std::chrono::seconds(0));
            // do something
        }
        while(  std::chrono::system_clock::now() < (tp1 + span) );
    
    
        if( s==future_status::ready)
            std::cout << "result is " << (f.get()? "Even": "Odd")  << '\n';
        else
            std::cout << "timeout " << '\n';
    
        t.join();         
    }