Понимание того, как многопоточность работает с Boost io_service - PullRequest
0 голосов
/ 17 апреля 2020

Я изучаю многопоточность и библиотеки Boost (в частности, Asio), и мне трудно понять, как работает следующий код (немного измененный из учебных пособий Boost.org)

#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>

class printer
{
public:
  printer(boost::asio::io_service& io)
    : timer1_(io, boost::posix_time::seconds(1)),
      timer2_(io, boost::posix_time::seconds(1)),
      count_(0)
  {
    timer1_.async_wait(boost::bind(&printer::print1, this));

    timer2_.async_wait(boost::bind(&printer::print2, this));
  }

  ~printer()
  {
    std::cout << "Final count is " << count_ << std::endl;
  }

  void print1()
  {
    if (count_ < 10)
    {
      std::cout << "Timer 1: " << count_ << std::endl;
      ++count_;

      timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(2));

      timer1_.async_wait(boost::bind(&printer::print1, this));
    }
  }

  void print2()
  {
    if (count_ < 10)
    {
      std::cout << "Timer 2: " << count_ << std::endl;
      ++count_;

      timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(2));

      timer2_.async_wait(boost::bind(&printer::print2, this));
    }
  }

private:
  boost::asio::deadline_timer timer1_;
  boost::asio::deadline_timer timer2_;
  int count_;
};

void saysomething()
{
    std::string whatyasay;
    std::cin >> whatyasay;
    std::cout << "You said " << whatyasay << std::endl;
}
int main()
{
  boost::asio::io_service io;
  printer p(io);
  boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
  io.run();
  std::cout << "Hey there\n";
  t.join();

  return 0;
}

Какие результаты в следующем выводе

Timer 1: 0
Timer 2: 1
Timer 1: 2
Timer 2: 3
Timer 1: 4
Timer 2: 5
Timer 1: 6
Timer 2: 7
Timer 1: 8
Timer 2: 9
Hey there
Final count is 10

Я ожидал от этого кода , что поток t будет отвечать за запуск io_service, что означает, что другие операции могут выполняться в То время.

Вместо код работает как обычно, aka, io.run «блокирует» поток кода до тех пор, пока таймеры внутри объекта принтера не прекратят запуск async_waits, поэтому «эй там» выводится только на печать после того, как таймеры больше не работают.

Но это еще не все: насколько я понимаю, io_services не прекращает работу после вызова метода run (), пока с ним связана работа (будь то работа) объект или, в данном случае, таймеры). С учетом вышесказанного, поскольку поток связан с io_service, мне интересно, почему io_service вообще перестал работать: в конце концов, поток «связан» с io_service и продолжает работать самостоятельно; это, очевидно, связано с тем фактом, что я явно не понимал, что этот поток делает в первую очередь.

Ситуация стала еще сложнее, когда я добавил метод "sayomething" в банк: я хотел быть в состоянии написать что-то и печатать эту строку, пока 2 таймера продолжали работать. Код, который я использовал, был следующий:

int main()
{
  boost::asio::io_service io;
  printer p(io);
  boost::thread t(&saysomething);
  io.run();
  std::cout << "Hey there\n";
  t.join();

  return 0;
}

со следующим результатом:

Timer 1: 0
Timer 2: 1
Timer 1: 2
Timer 2: 3
Timer 1: 4
Timer 2: 5
Timer 1: 6
Timer 2: 7
ghg       //<--- my input
You said ghg
Timer 1: 8
Timer 2: 9
Hey there
Final count is 10

Он работает нормально, но теперь, когда нет никакого потока, связанного с io_service, что было его Во-первых, цель?

Подводя итог, я задаю 3 вопроса:

  • Почему строка «Hey there» не выводится сразу, а не ожидает остановки работы io_service ?
  • Как именно io_service перестает работать, если с ним связан поток, что должно быть эквивалентно io_service, выполняющему работу?
  • Так как поток не разрешал "код" поток ", чтобы двигаться вперед, и связывание указанного потока с моим методом вместо io_service не вызвало никакой ошибки, какова была цель этого потока с самого начала?

1 Ответ

1 голос
/ 17 апреля 2020
  • Почему строка "Hey there" не печатается сразу, а не ожидает остановки работы io_service? Поток

main также блокируется на io_service перед печатью, поэтому «Привет!» не печатает, пока сервис не остановится.

  • Как именно io_service перестает работать, если с ним связан поток, что должно быть эквивалентно io_service, выполняющему работу?

Поток не тот, который поддерживая io_service в живых, задачи таймера. На самом деле io_service поддерживает живую нить здесь. Работа, выполняемая службой, ожидает таймеров, поэтому, пока не истечет время таймеров, у службы есть работа.

  • Поскольку поток не позволял «потоку кода» двигаться вперед, а привязка указанного потока к моему методу вместо io_service не вызывала ошибок, какова была цель этого потока во-первых?

Цель вызова run из потока - пожертвовать этот вызывающий поток в io_service. До выхода run служба владеет этим потоком, и этот поток является частью пула потоков службы. Любая задача, которую вы публикуете в сервисе, может быть передана этому потоку, пока он находится в пуле сервиса. Когда вы добавили второй поток, этот второй поток вообще не взаимодействовал со службой, потому что он не вызывал run. Таким образом, он не является частью пула потоков службы.

...