Question

I am currently working on a C++ app that runs on my PC just fine and I want to make it work on a BeagleBone Black on which I have already installed a Debian Wheezy.

I'm cross compiling using ELDK v5.3 and qmake from my PC (Intel Celeron, Debian Wheezy, boost v1.49.0-3.2) to the BeagleBone Black (ARM Cortex A8, Debian Wheezy, boost v1.49.0-3.2).

Everything works like it should, but every now and then, my app freezes (is stuck on a __pthread_mutex_lock) when a boost::thread is created or the app is waiting for a boost::thread::join(). I just want to understand what's going on.

If you have some tips that can help me secure these calls to boost::thread (try/catch, error status check ...) please share them :)

Thank you !!

Here is a small source code that freezes in a similar fashion when executed on the BeagleBone Black followed by the backtrace printed when the app freezes (GDB) and the .pro file used when executing the qmake command :

#include <stdio.h>
#include <boost/thread.hpp>

#define NB_THREADS              20
#define THREAD_LIFE_DURATION    5

int g_nb_thread = 0;

boost::thread * subRegisterThread(boost::thread * pthread)
{
    printf("Register thread #%d  %p created\n",
        g_nb_thread++, pthread);

    return pthread;
}

/////////////////// Sub dummy class

class sub_dummy_class
{
public:
    boost::thread *mThread;

    sub_dummy_class();
    ~sub_dummy_class();
    void loop();
    void start();
};



sub_dummy_class::sub_dummy_class()
{
    mThread = NULL;
}

sub_dummy_class::~sub_dummy_class()
{
    if(mThread)
    {
        mThread->join();
    }
}

void sub_dummy_class::start()
{
    mThread = subRegisterThread(new boost::thread(boost::bind(&sub_dummy_class::loop, this)));
}

void sub_dummy_class::loop()
{
    int life_duration = THREAD_LIFE_DURATION;
    while(life_duration > 0)
    {
        life_duration--;
        printf("Got %d seconds to live !\n", life_duration);
        usleep(1000000);
    }
    return;
}


////////////////////////// Dummy class

class dummy_class
{
public:

    sub_dummy_class dummies[NB_THREADS];

    dummy_class();
    ~dummy_class();
    void start();


};

dummy_class::dummy_class()
{

}

dummy_class::~dummy_class()
{

}

void dummy_class::start()
{
    for(int i = 0 ; i < NB_THREADS ; i++)
    {
        dummies[i].start();
    }
}


int main(int argc, char* argv[])
{
    printf("Starting program\n");

    printf("Creating dummy class\n");
    dummy_class *DC = new dummy_class();

    printf("Starting dummy class\n");
    DC->start();

    printf("Deleting dummy class\n");
    delete DC;

    return 0;
}

Stack trace :

(gdb) bt
#0  __libc_do_syscall () at ../ports/sysdeps/unix/sysv/linux/arm/eabi/libc-do-syscall.S:44
#1  0xb6756f92 in __lll_lock_wait (futex=0x1881c, private=0) at ../ports/sysdeps/unix/sysv/linux/arm/nptl/lowlevellock.c:47
#2  0xb675357a in __pthread_mutex_lock (mutex=0x1881c) at pthread_mutex_lock.c:61
#3  0xb68029dc in pthread_mutex_lock (mutex=<optimized out>) at forward.c:182
#4  0xb6991710 in lock (this=0xb69a2c68) at ./boost/smart_ptr/detail/spinlock_pt.hpp:41
#5  scoped_lock (pv=0x1f714, this=<synthetic pointer>) at ./boost/smart_ptr/detail/spinlock_pool.hpp:65
#6  atomic_increment (pw=0x1f714) at ./boost/smart_ptr/detail/sp_counted_base_spin.hpp:41
#7  add_ref_copy (this=0x1f710) at ./boost/smart_ptr/detail/sp_counted_base_spin.hpp:90
#8  shared_count (r=..., this=<optimized out>) at ./boost/smart_ptr/detail/shared_count.hpp:316
#9  shared_ptr (this=<optimized out>) at ./boost/smart_ptr/shared_ptr.hpp:164
#10 operator= (r=..., this=0x1f604) at ./boost/smart_ptr/shared_ptr.hpp:311
#11 boost::thread::start_thread (this=0x1f5e8) at libs/thread/src/pthread/thread.cpp:185
#12 0x0000cf7c in boost::thread::thread<boost::_bi::bind_t<void, boost::_mfi::mf0<void, sub_dummy_class>, boost::_bi::list1<boost::_bi::value<sub_dummy_class*> > > > (this=0x1f5e8, f=...)
    at /opt/eldk-5.3/armv7a-hf/sysroots/armv7ahf-vfp-neon-linux-gnueabi/usr/include/boost/thread/detail/thread.hpp:205
#13 0x0000aa44 in sub_dummy_class::start (this=0x1cfdc) at main.cpp:51
#14 0x0000abc4 in dummy_class::start (this=0x1cf90) at main.cpp:96
#15 0x0000ac44 in main (argc=1, argv=0xbefff834) at main.cpp:109

EDIT : Here is the .pro file I'm using for the qmake command (qmake -spec linux-armv7a-hf-g++) :

# .pro for test_boost
TEMPLATE = app
CONFIG =

QT -= qt webkit

TARGET = test_boost_ARM
QMAKE_LFLAGS += -Wl,-rpath ./
QMAKE_LFLAGS_RPATH =

HEADERS =
SOURCES = main.cpp

OTHER_FILES =

DESTDIR = .

# external libs
LIBS += -lboost_thread

I tested these two parameters a bit. When NB_THREADS=15, it seems to go just fine every time but when it's equal to 16, it often freezes. THREAD_LIFE_DURATION doesn't seem to have any effect on the program's behaviour. I hope it will help someone understand what's going on.

Was it helpful?

Solution

Looks like an upgrade of boost to version 1.54 fixes the issue. Took some time to get the right packages because Debian Wheezy's boost stable release is 1.49, so I had to manually upgrade my cross-compilation platform.

The app can now run up to 380 threads without any problems, this is more than enough for me.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top