【问题标题】:Boost::Thread function leading to a segmentation fault on an embedded ARMBoost::Thread 函数导致嵌入式 ARM 上的分段错误
【发布时间】:2012-02-14 15:48:04
【问题描述】:

我在使用 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 处理器的嵌入式服务器上运行。我有一个嵌入式系统制造商提供的交叉编译工具链,当我使用它进行交叉编译时,我得到一个段错误。通过调试,我发现在调用 s->update () 时会发生此段错误(或任何其他尝试取消引用共享指针并对它执行某些操作)。但是,如果我引入一点延迟,比如添加“sleep(1);”在我的 Sensor_Thread::update 函数中开始 while 循环之前,它可以完美运行。

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

谢谢!!!

【问题讨论】:

  • 您对教科书的信心令人着迷。 :)

标签: c++ multithreading boost segmentation-fault arm


【解决方案1】:
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

【讨论】:

  • 谢谢!添加入门方法应该很容易。正如您可能会说的,我是多线程编程的新手,我基于我在网上找到的一个示例......我可能对互斥锁有点困惑。我的目标是在 s->update () 方法运行时不让其他任何东西访问对象 s 指向的对象(s 是共享指针)。 nanosleep 函数只是设置更新间隔,绝对不必在互斥锁内......关于如何最好地实现我的目标的任何见解?
  • 您可以消除 scoped_lock 并在 update 之前锁定互斥锁,然后再解锁。或者,您可以将 scoped_lock 和 update 调用放在 if 1 块中。 (如果其他线程 modify s,也将这两个计算放入锁中。否则,无论哪种方式都无关紧要,尽管一般规则是为尽可能少的指令保留一个互斥锁可能。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-26
  • 1970-01-01
  • 2017-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多