Share_ptr的boost::线程断言失败

share_ptr of boost::thread assertion fail

本文关键字:线程 失败 断言 boost ptr Share      更新时间:2023-10-16
class WIFITest
{
public:
  void StartTest();
  void Notify_Test(boost::shared_ptr<basic_msg> basic_msg, ID id );

private:
  void OpenStaMode_test();
private: 
  boost::shared_ptr<boost::thread> OpenStaMode_testThread;
  boost::shared_ptr<basic_msg> VMF_WIFI_NOTIFY_CLIENT_OPEN_MSG;  
  typedef boost::shared_ptr<boost::thread> THREAD;
  typedef boost::shared_ptr<basic_msg> MSG;
  std::map<ID,std::pair<THREAD,MSG>> map;
};  
void WIFITest::StartTest()
{ 
  map[ID::WIFI_REQ_CLIENT_OPEN] = std::make_pair(OpenStaMode_testThread,VMF_WIFI_NOTIFY_CLIENT_OPEN_MSG);
  this->OpenStaMode_testThread.reset(new boost::thread(&WIFITest::OpenStaMode_test,this));
  this->OpenStaMode_testThread->join();
}
void WIFITest::OpenStaMode_test()
{
  unsigned char strData[WIFI_SEND_BUF_SIZE_MIN];
  sendOpenReq(strData);
  try { 
    boost::this_thread::sleep(boost::posix_time::seconds(8));
  }
  catch(const boost::thread_interrupted&) {   
        std::cout<<"OpenStaMode_test success@ n";
      }
    else {
        goto OpenStaMode_test_fail;
      }
    return;
  }
OpenStaMode_test_fail:
  printf("@WIFITest::OpenStaMode_test FAIL@@@@@@@@@@@@@@ n");
}
void WIFITest::Notify_Test(boost::shared_ptr<basic_msg> basic_msg, ID id)
{
  map[id].second = basic_msg;
   map[id].first->interrupt();
  printf("@WIFITest::INTERRUPTED @@@@@@@@@@@@@@ n");
}

第一个main将创建StartTest实例并调用StartTest(),当其他代码调用Notify_Test时,"map[id].first->interrupt();"这句话将产生以下断言失败,并使程序崩溃。

TestWIFI: ../../boost_1_55_0/boost/smart_ptr/shared_ptr.hpp:653: typename boost::detail::sp_member_access::type boost::shared_ptr::operator->() const [with T = boost::thread, typename boost::detail::sp_member_access::type = boost::thread*]:断言' px != 0'失败。

这一行:

map[ID::WIFI_REQ_CLIENT_OPEN] = std::make_pair(OpenStaMode_testThread,VMF_WIFI_NOTIFY_CLIENT_OPEN_MSG);

OpenStaMode_testThread的副本存储到映射中,此时该副本为空。

然后在OpenStaMode_testThread上调用reset(new boost::thread(&WIFITestSuite::OpenStaMode_test,this)),但这并不影响已经存储到映射中的副本。

因此,当您调用map[id].first->interrupt();时,您是在一个空的shared_ptr上调用它,从而导致断言失败。


如下所述,如果调用Notify_Test可以在线程开始执行之后发生,但在shared_ptr上的reset()调用将其存储到映射中之前发生,则存在竞争条件。要解决这个问题,可以使用互斥锁:

class WIFITest
{
public:
  /* ... */
private:
  /* ... */
private: 
  boost::mutex mutex_;
  /* ... */
};  

void WIFITest::StartTest()
{ 
  {
    boost::lock_guard<boost::mutex> guard(mutex_);  // Takes ownership of the mutex
    map[ID::WIFI_REQ_CLIENT_OPEN] = std::make_pair(THREAD(), VMF_WIFI_NOTIFY_CLIENT_OPEN_MSG);
    map[ID::WIFI_REQ_CLIENT_OPEN].first.reset(new boost::thread(&WIFITest::OpenStaMode_test,this));
    // At this point the thread has started and the pointer has been stored into the map
  }  // guard is destructed and mutex released here 
     // so that we don't hold the mutex while waiting
     // for the thread to finish.
  map[ID::WIFI_REQ_CLIENT_OPEN].first->join();
}
/* ... */
void WIFITest::Notify_Test(boost::shared_ptr<basic_msg> basic_msg, ID id)
{
  boost::lock_guard<boost::mutex> guard(mutex_); // Takes ownership of the mutex
  map[id].second = basic_msg;
  map[id].first->interrupt();
  printf("@WIFITest::INTERRUPTED @@@@@@@@@@@@@@ n");
}