0

{boost 1.54}

All asio operations are happening on the same io_service which has it's run() called from several std::threads (thus a thread-pool)

struct Async : std::enable_shared_from_this<Async>
{
   boost::signals2::signal<void()> m_sig;

   void read()
   {
      auto self = shared_from_this();
      boost::asio::async_read_until(
               /*socket*/,
               /*bufferToCollectData*/,
               /*delimiter*/,
               [self]{self->onRead(..);}
               );
   }

   void onRead(..)
   {
      m_sig();
   }
};

struct Process : std::enable_shared_from_this<Process>
{
   std::shared_ptr<Async> m_shrPtrAsync;
   boost::signals2::connection m_connection;

   void start()
   {
      m_shrPtrAsync = std::make_shared<Async>();
      //m_shrPtrAsync->startUpThings();

      auto self = shared_from_this();
      m_connection = m_shrPtrAsync->m_sig.connect(
               [self]{self->slot();}
               );
   }

   void stop()
   {
      //this will not delete the slot and have to wait indefinitely until some operation happens on m_sig.
      //------------------------------- <2>
      m_connection.disconnect();

      //this should force the original slot deletion.
      m_connection = m_shrPtrAsync->m_sig.connect([this]{dummy();});
      m_connection.disconnect();
   }

   void dummy() {}

   void slot()
   {
      auto self = shared_from_this(); //-------------------- <1>
      //to not block the calling thread (Async's m_sig())
      m_strand.post(
               [self]{self->slotPrivateImpl();}
               );
   }

   void slotPrivateImpl() { /*Processing*/ }
};

//This is from the main thread outside the thread-pool
{//local scope begins
auto shrPtrProcess = std::make_shared<Process>();
shrPtrProcess->start();
//after sometime
shrPtrProcess->stop();
}//local scope ends. I want shrPtrProcess to delete the contained pointer here
//which should in turn delete the Async's pointer in shrPtrProcess->m_shrPtrAsync

Is this safe? When main thread executes shrPtrProcess->stop(); thus deleting the slot from the Async's m_sig and then comes out of the local scope, the last remaining reference to the shared_ptr to Process will have died thus destroying it, but other thread firing m_sig could have entered Process::slot() by then and about to execute line marked <1> above. Does signals2 guarantee that slots will not be deleted till they are executed completely?

If this is not safe then how do i achieve this behaviour of shrPtrProcess destroying Process ptr which in turn destroys Async raw ptr in shrPtrAsync once the local scope ends? If I don't do the hack in place marked <2> above I'll never be able to release resources if m_sig() does not fire anymore as signals2::connection::disconnect() does not cause immediate deletion of slot.

ustulation
  • 3,600
  • 25
  • 50
  • As far as I see, you always call `slot()` through `shared_ptr`, so there's at least 1 reference alive at this point. – Igor R. Oct 20 '13 at 14:19
  • This works btw - The dtor is invoked. From what i read in other posts, signal makes a copy of list of slots before invoking. So when signal executes slot() and stop() is called, the hack at mark <2> deletes the original slot functor and when slot() returns after posting for sloPrivateImpl() to take up further tasks, the temporary functor copy is destroyed too and now you have only one reference which will expire once sloPrivateImpl() execution is over and dtor will then be called - reference http://stackoverflow.com/a/2265979/1060004 and http://stackoverflow.com/a/4490785/1060004 – ustulation Oct 20 '13 at 15:43

0 Answers0