1

I want to know when dispatchhas finished with some specific work

service.dispatch(&some_work);

I want to know this because I need to restart some_work if it has finished.

struct work
{
  std::shared_ptr<asio::io_service> io_service;
  bool ready;
  std::mutex m;
  template <class F>
  void do_some_work(F&& f)
  {
    if (io_service && ready) {
      m.lock();
      ready = false;
      m.unlock();
      io_service->dispatch([&f, this]() {
        f();
        m.lock();
        ready = true;
        m.unlock();
      });
    }
  }
  work(std::shared_ptr<asio::io_service> io_service)
    : io_service(io_service)
    , ready(true)
  {
  }
};

int
main()
{
  auto service = std::make_shared<asio::io_service>();
  auto w = std::make_shared<asio::io_service::work>(*service);
  std::thread t1([&] { service->run(); });

  work some_work{ service };
  for (;;) {
    some_work.do_some_work([] {
      std::cout << "Start long draw on thread: " << std::this_thread::get_id()
                << std::endl;
      std::this_thread::sleep_for(std::chrono::seconds(5));
      std::cout << "End long draw on thread: " << std::this_thread::get_id()
                << std::endl;
    });
  }
  w.reset();
  t1.join();
}

There are some problems with the code, for example if some_workgoes out of scope, then the running taskwould still write to ready.

I am wondering if something like this already exists in Asio?

Maik Klein
  • 15,548
  • 27
  • 101
  • 197
  • 1
    As for the issue about the object going out of scope, how about using a shared pointer for the object as well, and pass it along to the `do_some_work` function? Then the object won't be destroyed until the function returns, – Some programmer dude Dec 25 '15 at 12:39
  • @JoachimPileborg By that you mean that the bool `ready` should be made a `shared_ptr`? – Maik Klein Dec 25 '15 at 12:46
  • No, I mean `some_work` should be a shared pointer, that you pass as an argument to the function. – Some programmer dude Dec 25 '15 at 12:50
  • @MaikKlein My answer contains links to samples. The second link shows exactly the two approaches (one using more shared_ptr all around, the other abstracting "some work" into a class (`CSession` in the sample). – sehe Dec 25 '15 at 12:51

1 Answers1

1

For lifetime issues, the common idiom is indeed to use shared pointers, examples:

Other than that, the completion handler is already that event. So you would do:

void my_async_loop() {
    auto This = shared_from_this();
    socket_.async_read(buffer(m_buffer, ..., 
        [=,This](error_code ec, size_t transferred) {
             if (!ec) {
                // do something
                my_async_loop();
             }
          }
      );
}

This will re-schedule an (other?) async operation once the previous has completed.

On the subject of threadsafety, see Why do I need strand per connection when using boost::asio?

Community
  • 1
  • 1
sehe
  • 374,641
  • 47
  • 450
  • 633