Читаем Параллельное программирование на С++ в действии полностью

Но просто вызывать функцию wait() особого смысла не имеет — как правило, нам нужно обработать полученное сообщение. Для этого предназначена функция-член handle() (3). Это шаблон, и тип сообщения нельзя вывести, поэтому необходимо явно указать, сообщение какого типа обрабатывается, и передать функцию (или допускающий вызов объект) для его обработки. Сама функция handle() передает очередь, текущий объект dispatcher и функцию-обработчик новому экземпляру шаблонного класса TemplateDispatcher, который обрабатывает сообщения указанного типа. Код этого класса показан в листинге С.5. Именно поэтому мы проверяем флаг chained в деструкторе перед тем, как приступить к ожиданию сообщения; он не только предотвращает ожидание объектами, содержимое которых перемещено, но и позволяет передать ответственность за ожидание новому экземпляру TemplateDispatcher.


Листинг С.5. Шаблон класса TemplateDispatcher

namespace messaging {

template<

 typename PreviousDispatcher, typename Msg, typename Func>

class TemplateDispatcher {

 queue* q;

 PreviousDispatcher* prev;

 Func f;

 bool chained;


 TemplateDispatcher(TemplateDispatcher const&) = delete;

 TemplateDispatcher& operator=(

  TemplateDispatcher const&) = delete;


 template<

  typename Dispatcher, typename OtherMsg, typename OtherFunc>

 friend class TemplateDispatcher;←┐Все конкретизации

 void wait_and_dispatch()         │TemplateDispatcher

 {                                │дружат между собой

  for (;;) {

   auto msg = q->wait_and_pop();

   if (dispatch(msg))←┐Если мы обработали

   break;             │сообщение выходим

  }                  

(1) из цикла

 }


 bool dispatch(std::shared_ptr const& msg) {

  if (wrapped_message* wrapper =

   dynamic_cast*>(

   msg.get())) {       ←┐Проверяем тип

   f(wrapper->contents);│сообщения и

   return true;         │вызываем

  }                    (2) функцию

  else {

   return prev->dispatch(msg);←┐Вызываем предыдущий

  }                           (3) диспетчер в цепочке

 }


public:

 TemplateDispatcher(TemplateDispatcher&& other):

  q(other.q), prev(other.prev), f(std::move(other.f)),

  chained(other.chained) {

  other.chained = true;

 }


 TemplateDispatcher(

  queue* q_, PreviousDispatcher* prev_, Func&& f_):

  q(q_), prev(prev_), f(std::forward(f_)), chained(false)

 {

  prev_->chained = true;

 }


 template

 TemplateDispatcher

 handle(OtherFunc&& of)←┐Дополнительные обработчики

 {                     (4) можно связать в цепочку

  return TemplateDispatcher<

   TemplateDispatcher, OtherMsg, OtherFunc>(

    q, this, std::forward(of));

 }


 ~TemplateDispatcher() noexcept(false)←┐Деструктор снова

 {                                     │помечен как

  if (!chained) {                     (5) noexcept(false)

   wait_and_dispatch();

  }

 }

};

}

Шаблон класса TemplateDispatcher<> устроен по образцу класса dispatcher и почти ничем не отличается от него. В частности, деструктор тоже вызывает wait_and_dispatch(), чтобы дождаться сообщения.

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии