From: andreas_m_huber (andreas_at_[hidden])
Date: 2002-01-03 18:31:28


Hello there

I had a quick look at the new Signals library and I'm having
difficulties how to safely use it in an MT environment. For example,
if not used _very_ carefully, the proposed boost::trackable baseclass
seems to make otherwise inncocent-looking code vulnerable to race
conditions.

Example (derived from the signals library documentation, does not
compile):

struct Provider {
  Provider( const std::string & name ) : name( name ) {}

  boost::signal1< void, const std::string & > SomeSignal;

  void DoIt() { SomeSignal( name ); }

private:
  std::string name;
};

struct SomeSlot : public boost::trackable {
  // connects itself with the passed provider and relies on the
  // base class destructor to be disconnected
  SomeSlot( Provider & provider ) {
    provider.SomeSignal.connect(
      boost::bind( &SomeSlot::DoIt, this, _1 ) );
  }

  void DoIt( const std::string & );

private:
  // some Mutex protected members accessed by DoIt
};

Provider myProvider( "OK!" );
SomeSlot * pSlot = new SomeSlot( myProvider );

myProvider.DoIt(); // prints OK!

// here pSlot is handed to thread 2
delete pSlot; // executed by thread 2

myProvider.DoIt(); // executed by thread 1

The base class portion of an object is destructed after the derived
class members, so the following could occur:
- thread 2 has already destructed the members of SomeSlot but has not
yet destructed the boost::trackable base class.
- thread 1 fully executes myProvider.DoIt() before thread 2 has a
chance to complete the destruction of the object (and thus

remove the SomeSlot object from the slot list).

--> Thread 1 accesses the already destructed subobject(s) of SomeSlot.

I cannot see how to _easily_ avoid this problem if one solely relies
on boost::trackable for connection management.

I believe the same thing could happen even if manual connection
management is used (although less likely): One thread makes a
"call" through the signal while another thread disconnects the slot.
It could AFAICT happen that the slot is called _after_ it has been
disconnected (which of course could lead to all sorts of problems).

IMPORTANT: This is not meant as a critisism to the signals library or
its designer. I (with my limited experience in multithreading) simply
cannot figure out how to use the library safely in an MT environment.

Andreas