#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;
}