Ошибка программы libpthread на C ++ по неизвестной причине - PullRequest
1 голос
/ 22 февраля 2010

У меня есть приложение, связанное с libpthread. Ядром приложения являются два FIFO, совместно используемые четырьмя потоками (два потока на один FIFO, то есть;). Класс FIFO синхронизируется с использованием мьютексов pthread и хранит указатели на большие классы (содержащие буферы размером около 4 КБ), размещенные внутри статической памяти, с использованием перегруженных операторов new и delete (здесь динамического выделения нет).

Сама программа обычно работает нормально, но время от времени происходит сбой без видимой причины. Проблема в том, что я не могу отладить segfaults должным образом, так как я работаю на встроенной системе со старым ядром Linux (2.4.29) и g ++ (версия gcc egcs-2.91.66 19990314 / Linux (egcs-1.1. 2 выпуска)).

В системе нет gdb, и я не могу запустить приложение в другом месте (оно слишком специфично для оборудования).

Я скомпилировал приложение с флагами -g и -rdynamic, но внешний gdb ничего не говорит мне, когда я проверяю файл ядра (только шестнадцатеричные адреса) - тем не менее я могу распечатать обратную трассировку из программы после перехвата SIGSEGV - она ​​всегда выглядит как это:

Backtrace for process with pid: 6279
-========================================-
[0x8065707]
[0x806557a]
/lib/libc.so.6(sigaction+0x268) [0x400bfc68]
[0x8067bb9]
[0x8067b72]
[0x8067b25]
[0x8068429]
[0x8056cd4]
/lib/libpthread.so.0(pthread_detach+0x515) [0x40093b85]
/lib/libc.so.6(__clone+0x3a) [0x4015316a]
-========================================-
End of backtrace

Так что, похоже, указывает на libpthread ...

Я запускал некоторые модули через valgrind, но не обнаружил утечек памяти (так как я едва использую динамическое выделение).

Я подумал, что, возможно, мьютексы вызывают некоторые проблемы (так как они блокируются / разблокируются примерно 200 раз в секунду), поэтому я переключил свой простой класс мьютексов:

class AGMutex {

    public:

        AGMutex( void ) {
            pthread_mutex_init( &mutex1, NULL );
        }

        ~AGMutex( void ) {
            pthread_mutex_destroy( &mutex1 );
        }

        void lock( void ) {
            pthread_mutex_lock( &mutex1 );
        }

        void unlock( void ) {
            pthread_mutex_unlock( &mutex1 );
        }

    private:

        pthread_mutex_t mutex1;

};

к классу фиктивного мьютекса:

class AGMutex {

    public:

        AGMutex( void ) : mutex1( false ) {
        }

        ~AGMutex( void ) {
        }

        volatile void lock( void ) {
            if ( mutex1 ) {
                while ( mutex1 ) {
                    usleep( 1 );
                }
            }
            mutex1 = true;
        }

        volatile void unlock( void ) {
            mutex1 = false;
        }

    private:

        volatile bool mutex1;

};

но это ничего не изменило и обратный след выглядит так же ...

После некоторого сеанса отладки oldchool "положить-между-каждой-строкой-и-увидеть-где-то-это-segfaults-плюс-запомнить-pids-и-вещи" кажется, что во время usleep происходит сбой (?).

Понятия не имею, что еще может быть не так. Он может работать в течение часа или около того, а затем внезапно отключиться от сети без видимой причины.

Кто-нибудь сталкивался с подобной проблемой?

Ответы [ 2 ]

1 голос
/ 22 февраля 2010

От моего ответа до Как создать трассировку стека при сбое моего приложения gcc C ++ :

    The first two entries in the stack frame chain when you get into the 
    signal handler contain a return address inside the signal handler and
    one inside sigaction() in libc.  The stack frame of the last function
    called before the signal (which is the location of the fault) is lost.

Это может объяснить, почему у вас возникают трудности с определением местоположения вашего сегфоутла через обратную трассировку от обработчика сигнала. Мой ответ также включает обходной путь для этого ограничения.

Если вы хотите увидеть, как ваше приложение на самом деле расположено в памяти (например, 0x80..... адреса), вы сможете создать файл map из gcc. Обычно это делается через -Wl,-Map,output.map, который передает -Map output.map компоновщику.

У вас также может быть аппаратная версия objdump или nm с вашей цепочкой инструментов / кросс-цепочкой, которая может быть полезна при расшифровке ваших 0x80..... адресов.

0 голосов
/ 26 февраля 2010

Есть ли у вас доступ к Helgrind на вашей платформе? Это инструмент Valgrind для обнаружения ошибок потоков POSIX, таких как расы и потоки, удерживающие мьютексы при выходе.

...