【问题标题】:Which is the best way to yield thread?哪个是产生线程的最佳方法?
【发布时间】:2019-10-12 23:12:24
【问题描述】:

程序语言:C++ 11
我使用管道线程模式来处理数据。
一个线程生成数据。
单线程处理数据。
虽然没有要处理的数据,但哪种方式是产生线程的最佳方式?
现在我用

std::this_thread::sleep_for(100ms); 
  1. 不知道有没有更好的屈服方式?
  2. 如果睡眠足够好,睡多长时间比较好?

【问题讨论】:

  • 这不是屈服。您需要的是线程需要等待的等待条件。见stackoverflow.com/questions/10974829/…
  • 为什么是 pi 标签?
  • 你需要使用线程同步(mutex,condition_variable),请让给操作系统。

标签: c++ multithreading c++11


【解决方案1】:

产生线程的最佳方法是什么?

std::this_thread::yield

现在我用

std::this_thread::sleep_for(100ms);

虽然睡眠确实会产生线程作为副作用,但这还不是全部。顾名思义,它会在给定时间内阻塞线程。

但是,目前尚不清楚在您所描述的生产者/消费者案例中,屈服或休眠如何有用。您可能应该做的是等待条件变量。

【讨论】:

    【解决方案2】:

    引入消费者线程需要等待的等待条件。 生产者生成数据后,它可以通知您的消费者线程,直到消费者等待。

    【讨论】:

      【解决方案3】:

      通过数据队列进行通信。如果需要,队列可以有一个最大大小。

      一个线程生成数据并将其推入队列。

      另一个线程从队列中弹出数据,并对其进行处理。

      当队列为空时,消费线程在队列中等待推送新数据。

      当队列已满时,生产线程在队列中等待弹出数据。或者,您可以丢弃并替换队列中的等待数据。这取决于您的数据模型是什么样的(最近的很重要,或者按顺序排列的所有内容都很重要)

      简单队列:

      template<class T>
      struct threadsafe_queue {
        T pop() {
          auto l = lock();
          cv.wait( l, [&]{ return !data.empty(); } );
          T r = std::move(data.front());
          data.pop_front();
          return r;
        }
        void push( T&& t ) {
          auto l = lock();
          data.push_back( std::move(t) );
          cv.notify_one();
        }
        void abandon() {
          auto l = lock();
          data = {};
        }
      private:
        std::unique_lock<std::mutex> lock() { return std::unique_lock<std::mutex>(m); }
      
        std::mutex m;
        std::condition_variable cv;
        std::deque<T> data;
      };
      

      条目数量有限制的应该有第二个 condition_variable 来通知有人弹出,并且 push 应该看看你是否达到了限制。

      支持“满时覆盖”成为另一种选择。 1 元素“最新”看起来像:

      template<class T>
      struct mono_threadsafe_queue {
        // waits until we have data, then returns it.
        T pop() {
          auto l = lock();
          cv_hasdata.wait( l, [&]{ return (bool)data; } );
          T r = std::move(*data);
          data = boost::none;
          cv_hasroom.notify_one();
          return r;
        }
        // waits for there to be room if there is none.
        void push( T&& t ) {
          auto l = lock();
          cv_hasroom.wait( l, [&]{ return !(bool)data; } );
          data =  std::move(t);
          cv_hasdata.notify_one();
        }
        void replace( T&& t ) {
          auto l = lock();
          data =  std::move(t);
          cv_hasdata.notify_one();
        }
        // replaces data if f returns true, or if there is no data
        // imagine data with a timestamp, and we only want to replace it with
        // newer data
        template<class F>
        void replace_if( T&& t, F&& f ) {
          auto l = lock();
          if (!data || !f(*data))
          {
            data =  std::move(t);
            cv_hasdata.notify_one();
          }
        }
        void abandon() {
          auto l = lock();
          data = boost::none;
          cv_hasroom.notify_one();
        }
      
      private:
        std::unique_lock<std::mutex> lock() { return std::unique_lock<std::mutex>(m); }
      
        std::mutex m;
        std::condition_variable cv_hasdata;
        std::condition_variable cv_hasroom;
        boost::optional<T> data;
      };
      

      【讨论】:

        猜你喜欢
        • 2023-01-30
        • 2020-07-26
        • 2016-12-21
        • 2016-06-12
        • 2015-07-16
        • 2020-05-13
        • 2012-01-29
        • 2018-10-13
        • 2011-12-03
        相关资源
        最近更新 更多