Boost::线程函数导致嵌入式ARM上的分段故障

Boost::Thread function leading to a segmentation fault on an embedded ARM

本文关键字:故障 ARM 分段 线程 函数 Boost 嵌入式      更新时间:2023-10-16

我在使用Boost::threads的线程类中遇到了一个奇怪的问题。以下是我正在做的事情的简要总结:

例程创建一组对象,这些对象由具有私有数据成员的处理程序类组成,该私有数据成员是指向基类的共享指针,该基类形成继承树。我很有信心这个程序是正确的,而不是问题的一部分。

然后,我调用处理程序类(startUpdate)的一个方法,该方法将创建我的线程类的一个新实例。这是线程类代码:

class Sensor_Thread
{
  public:
    //constructor (creates thread and binds the update function to it
    Sensor_Thread (const Ptr<Sensor_Base> & theSensor): m_stoprequested (false),
                      s (theSensor),
                      m_thread (boost::bind (&Sensor_Thread::update, this)) { }
    //default null constructor, shouldn't ever be used
    Sensor_Thread (): m_stoprequested (true),
                      m_thread (),
                      s (NULL) { }
    //destructor (automatically joins the thread as per RAII principles)
    ~Sensor_Thread () { m_stoprequested = true; m_thread.join (); }
  private:
    volatile bool m_stoprequested;
    boost::mutex m_mutex;
    boost::thread m_thread;
    Ptr<Sensor_Base> s;
    void update ();
};

("Ptr"类是我的共享指针类……我很有信心它能正确工作,因为我最初是从C++教科书中得到的……)

更新功能:

void Sensor_Thread::update ()
{
  //make sure we actually have a sensor attached...
  if (s) { 
    // set up structure for sleeping
    struct timespec time;
    while (!m_stoprequested)
    {
      boost::mutex::scoped_lock lock(m_mutex);
      s->update ();
      time.tv_sec = s->updateInterval / 1000;
      time.tv_nsec = (1000 % s->updateInterval) * (1000 * 1000);
      nanosleep (&time, NULL);
    }
  }
}

这将无限期运行,直到驱动程序中的另一个触发器调用stopUpdate并且threaded_class被销毁。

奇怪之处:在我的OS X 10.6开发盒上,使用darwin gcc 4.2.1,它运行良好,完全符合预期。

这意味着在使用debian-linux和ARM处理器的嵌入式服务器上运行。我有一个由嵌入式系统制造商提供的交叉编译工具链,当我使用它进行交叉编译时,我会得到一个seg错误。通过调试,我发现这个seg错误发生在调用s->update()时(或者任何其他试图取消引用共享指针并对其执行操作的尝试)。然而,如果我引入了一个轻微的延迟,比如在Sensor_Thread::update函数中启动while循环之前添加"sleep(1);",它可以完美地工作。

在我看来,这似乎意味着系统试图在完全或充分初始化之前取消引用共享指针s?sleep(1)的变通方法使它能够工作,但对我来说,这似乎非常奇怪。如果线程类的共享指针在构造函数期间初始化,那么在调用更新函数之前,它不应该准备好吗?或者boost::thread的创建是否意味着更新函数与线程类所拥有的共享指针的初始化同时发生?有没有比"睡眠"破解更干净的方法来确保在调用更新函数之前初始化共享指针?

谢谢!!!

Sensor_Thread (const Ptr<Sensor_Base> & theSensor): m_stoprequested (false),
                  s (theSensor),
                  m_thread (boost::bind (&Sensor_Thread::update, this)) { }

此代码已损坏。您正在对尚未构造的对象调用update。在构造函数的初始化列表中使用this应该始终引发一个红色标志。它是指向一个尚未完全存在的对象的指针。

通常的处理方法是将其分为两个步骤。使用runstart方法创建线程。在构造函数返回后调用该方法。

while (!m_stoprequested)
{
  boost::mutex::scoped_lock lock(m_mutex);
  s->update ();
  time.tv_sec = s->updateInterval / 1000;
  time.tv_nsec = (1000 % s->updateInterval) * (1000 * 1000);
  nanosleep (&time, NULL);
}

这可能不是你想要的。它总是保持互斥,使得另一个线程很难访问s。它必须等到下一次更新,然后才能赢得互斥锁的竞争。在一些平台上,一个正在进行实际工作的线程将很难击败一个"交互式"线程(一个主要是睡眠的线程)。因此,这可能会使试图访问s的任何其他线程的速度大大减慢。

为什么在持有互斥对象的情况下调用nanosleep