android pthread c = SIGSEGV

#c #android #pthreads

#c #Android #pthreads

Вопрос:

Следующий код компилируется и выполняется в стандартном Linux:

 #include <iostream>
#include <pthread.h>

using namespace std;

class Foo
{
    public:
        Foo();
        void go_thread();
        void stop_thread();
    private:
        static void* worker( void* param );
        pthread_t m_pt;
};

Foo::Foo()
{
    m_pt = 0;
}

void Foo::go_thread()
{
    int success = pthread_create( amp;m_pt, NULL, worker, static_cast<void*>(this) );

    if( success == 0 )
    {
        cout << "thread started" << endl;
    }
}

void Foo::stop_thread()
{
    int success = pthread_join( m_pt, NULL );

    if( success == 0 )
    {
        cout << "thread stopped" << endl;
    }
}

void* Foo::worker( void* p )
{
    cout << "thread running" << endl;
    return 0;
}

int main()
{
    Foo f;
    f.go_thread();
    f.stop_thread();
    return 0;
}
  

и выдает следующий результат:

 $ ./a.out
thread started
thread running
thread stopped
$
  

Этот код также создается с помощью Android NDK (r5b). Однако, когда я adb загружаю результирующий исполняемый файл на устройство и запускаю его, я получаю SIGSEGV еще до запуска main(). Я выделил проблему до pthread_create() Похоже, что само существование этого вызова в моем коде, не говоря уже о выполнении, приводит к сбою моей программы в seg. Есть идеи?

Комментарии:

1. Ваша проверка на ошибки неверна. при успешном выполнении pthread_create amp; join вернет 0, в противном случае целое число, обозначающее ошибку. Возможно, у вас сбой по какой-то причине, и вы не знаете об этом.

2. да, хороший глазомер. Я исправил сообщение, но основная проблема все еще остается. Спасибо!

Ответ №1:

Возможно, это не так, но попробуйте заставить функцию, вызываемую pthread, создать обычную c-функцию (т. Е. Объявить ее как extern «C»), а не статическую функцию-член:

Это связано с тем, что технически соглашение о вызовах для статических членов может отличаться от соглашения о вызовах C, используемого C-библиотекой pthread (хотя во многих случаях они одинаковы (вот почему это работает в вашем linux-блоке), на мой взгляд, это не стоит риска переноса).

 extern "C" void* start_the_thread(void*);

void* start_the_thread(void* data)
{
    Foo*  theObject = static_cast<Foo*>(data);
    // In Java if your Foo had been derived from Runable
    // This is s where theObject->run() would have been called.
    return Foo::worker(data);
}

int success = pthread_create( amp;m_pt, NULL, start_the_thread, static_cast<void*>(this)
  

Комментарии:

1. [basic.compound] и [expr.unary.op] постановляем, что указатели на статические элементы взаимозаменяемы с указателями на свободные функции. Это не полностью исключает несовместимость с extern "C" соглашением о вызовах, но вам понадобится какое-то другое исправление, зависящее от конкретной реализации, чтобы изменить соглашение о вызовах.

2. @Ben: Функции на C . Не функции C (он же внешний «C»). Обратите внимание, что pthread является библиотекой C и, следовательно, использует соглашение о вызовах «C» для указателей, которые она получает. Оказавшись внутри функции start_the_thread(), мы, конечно, можем вызвать статическую функцию-член обычным способом.

3. @Martin: Правильно, языковая привязка является частью типа указателя на функцию. Но тип исправляется применением extern "C" связи, а не перемещением функции за пределы класса. И поскольку это несоответствие типов, компилятор должен был выдать ошибку — указатели на функции никогда не преобразуются неявно.

4. @Ben: Я не знал, что вы можете применить внешнюю привязку «C» к статическому методу-члену. Если вы сможете, это решит проблему. Но поскольку я не думаю, что вы можете (я могу ошибаться), решение должно заключаться в том, чтобы переместить его за пределы класса. Это не ошибка компиляторов (типы идентичны (привязка — это то, как они вызываются, а не часть типа)), я никогда не видел, чтобы компилятор выдавал это как ошибку, но я видел эту точную проблему много раз раньше. Это ставка 50/50 на возможности между соглашениями о вызовах. Примечание: как и 80% статистики, 50/50 складывается (давайте просто назовем это взвешенным подбрасыванием монеты).

5. @Martin: Вы не можете применить extern "C" к функции-члену (статической или иной). Но быть бесплатной функцией недостаточно. В любом случае, если указатель на функцию, сформированный из функции C , был несовместим с pthread_create , компилятор обязан отклонить программу. Стандарт не разрешает неявное преобразование указателей на функции, и эта диагностика не является обязательной.

Ответ №2:

Похоже, проблема заключается в объединении iostream с pthread. Я просмотрел и заменил все варианты на printf()s, удалил предложение using и удалил заголовок iostream. Код скомпилирован и запущен без проблем на устройстве. Интересно, следует ли информировать об этом Google?

Окончательный (рабочий) код выглядит следующим образом:

 #include <pthread.h>
#include <stdio.h>

class Foo
{
    public:
        Foo();
        void go_thread();
        void stop_thread();
    private:
        static void* worker( void* param );
        pthread_t m_pt;
};

Foo::Foo()
{
    m_pt = 0;
}

void Foo::go_thread()
{
    int success = pthread_create( amp;m_pt, NULL, worker, static_cast<void*>(this) );

    if( success == 0 )
    {
        printf( "thread startedn" );
    }
}

void Foo::stop_thread()
{
    int success = pthread_join( m_pt, NULL );

    if( success == 0 )
    {
        printf( "thread stoppedn" );
    }
}

void* Foo::worker( void* p )
{
    printf( "thread runningn" );
    return 0;
}

int main()
{
    Foo f;
    f.go_thread();
    f.stop_thread();
    return 0;
}