Domanda

this is a paste from threadsanitazer (clang) which reports data race http://pastebin.com/93Gw7uPi

Googling around it seems this is a problem with threadsanitazer (for example http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57507)

So lets say this looks like (written by hand just now for this so it's not working code):

class myclass : : public std::enable_shared_from_this<myclass>
{
  public:  // example!
  myclass(boost::asio::io_service &io, int id);
  ~myclass() { /*im called on destruction properly*/ }
  void start_and_do_async();
  void stop();

  int ID;
  boost::asio::udp::socket usocket_;
  ... endpoint_;
  ... &io_;
}

typedef std::shared_ptr<myclass> myclass_ptr;
std::unordered_map<int, myclass_ptr> mymap;

myclass::myclass(boost::asio::io_service io, int id) : io_(io)
{
  ID = id;
}

void myclass::start_and_do_async()
{
   // do work here 

  //passing (by value) shared_ptr from this down in lambda prolongs this instance life
  auto self(shared_from_this()); 
  usocket_.async_receive_from(boost::asio::buffer(...),endpoint,
  [this,self](const boost::system::error_code &ec, std::size_t bytes_transferred)
  {
    start_and_do_async();
  }
}

void myclass::stop()
{ 
  // ...some work and cleanups
  usocket_.close();
}

in main thread new thread is created (this is in another class actually) and run for new io_service handlers

new boost::thread([&]()
{   
     boost::asio::io_service::work work(thread_service);
     thread_service.run();
}); 

and from the main thread element gets added or removed periodically

void add_elem(int id)
{
  auto my = std::make_shared<my>(thread_service, id);
  my->start();
  mymap[id] = my;
}

void del_elem(int id)
{ 
  auto my = mymaps.at(id);
  mymap.erase(id); //erase first shared_ptr instace from map

  // run this in the same thread as start_and_do_async is running so no data race can happen (io_service is thread safe in this case)
  thread_service.post[my]()
  {
    my.stop(); //this will finally destroy myclass and free memory when shared_ptr is out of scope
  });
}

So in this case and judging by the docs (where it states that distinct shared_ptr (boost or std) allows read/write access from multiple threads) can there be a data race?

Does this code properly create two distinct shared_ptr instaces for one pointer?

In shared_ptr.h I can see atomic operations so I just want a confirmation that it is problem with thread sanitazer reporting false positives.

In my tests this works correctly with no memory leakage (shared_ptr instances are removed properly and destructor is called), segfaults or anything else (10 hours inserting/deleting elements - 100 per second or 1 by second)

È stato utile?

Soluzione

Assuming the shared_ptr thread safety documentation matches its implementation, then the report of a data race on the shared_ptr is a false-positive. The threads operate on distinct instances of shared_ptr that share ownership of the same instance. Hence, there is no concurrent access of the same shared_ptr instance.

With that said, I do want to stress that in the example, the thread safety of myclass::usocket_ is dependent on only a single thread processing the io_service, effectively executing in an implicit strand. If multiple threads service the io_service, then an explicit strand can be used to provide thread safety. For more details on some of the thread safety subtleties with Boost.Asio and strands, consider reading this answer.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top