【问题标题】:share_ptr of boost::thread assertion failboost::thread 断言的 shared_ptr 失败
【发布时间】:2014-06-25 06:25:54
【问题描述】:
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*]: Assertion `px != 0' failed.

【问题讨论】:

    标签: c++ multithreading boost smart-pointers boost-thread


    【解决方案1】:

    这一行:

    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(&amp;WIFITestSuite::OpenStaMode_test,this)),但这不会影响已存储到地图中的副本。

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


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

    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");
    
    }
    

    【讨论】:

    • 谢谢,如何修改我的代码?我需要先将 OpenStaMode_testThread 存储在地图中。
    • 在启动 OpenStaMode_testThread 之前我需要匹配 id 和线程
    • @huskarwang 为什么需要在地图中存储一个空的shared_ptr?另外,何时调用Notify_Test 是否有任何保证?如果答案是“线程启动后的任何时间”,那么这里就有竞争条件。
    • @T.C.像这样的东西?那么我不再需要 OpenStaMode_testThread 作为成员了吗?map[WIFI_REQ_ID::WIFI_REQ_CLIENT_OPEN].first.reset(new boost::thread(&WIFITestSuite::OpenStaMode_test,this));
    • 我不想存储空的shared_ptr,我希望map中的指针和中断指针是同一个指针。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 1970-01-01
    相关资源
    最近更新 更多