Какой лучший способ дать нить? - PullRequest
0 голосов
/ 27 мая 2019

Язык программы: C ++ 11
Я использую режим потоков конвейера для обработки данных.
Один поток генерирует данные.
Один поток обрабатывает данные.
Пока нет данных для сделки, какой лучший способ вывести поток?
Теперь я использую

std::this_thread::sleep_for(100ms); 
  1. Интересно, есть ли лучший способ уступить?
  2. Если сон достаточно хорош, как долго лучше спать?

Ответы [ 3 ]

6 голосов
/ 27 мая 2019

Какой лучший способ получить нить?

Это std::this_thread::yield.

Теперь я использую

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

Хотя сон приводит к тому, что нить является побочным эффектом, это еще не все.Как следует из названия, он блокирует поток на определенное время.

Однако неясно, как уступка или усыпление будут полезны в случае производителя / потребителя, например, того, что вы описываете.Что вы, вероятно, должны сделать, это вместо этого ждать условную переменную.

2 голосов
/ 27 мая 2019

Введите условие ожидания, при котором ваш потребительский поток должен ждать.Как только данные сгенерированы производителем, он может уведомить ваш потребительский поток, пока потребитель не ждет.

1 голос
/ 27 мая 2019

Общение через очередь данных.При желании очередь может иметь максимальный размер.

Один поток генерирует данные и помещает их в очередь.

Другой поток извлекает данные из очереди и обрабатывает их.

Когда очередь пуста, потребляющий поток ожидает в очереди новых данных для отправки.

Когда очередь заполнена, производящий поток ожидает в очереди данных, которые будут извлечены.Кроме того, вы можете отбросить и заменить ожидающие данные в очереди.Зависит от того, на что похожа ваша модель данных (важна последняя или важна вся последовательность)

Простая очередь:

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;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...