pthread_join периодически вылетает из-за ошибки сегментации в OSX

#multithreading #macos #thread-safety #pthreads

#многопоточность #macos #безопасность потоков #pthreads

Вопрос:

Я получаю ошибку сегментации при присоединении к дочернему потоку, и я исчерпал все варианты, которые я мог придумать для отладки, просматривая Stack-overflow и остальной Интернет! 🙂 Я буду настолько тщательным, насколько смогу. Код написан на C и скомпилирован с помощью GNU GCC в OSX 10.6.8. Я связался с библиотекой ‘pthread’, используя параметр ‘-pthread’. Я также пробовал ‘-lphtread’. Никакой разницы.

Я использую следующие глобальные переменные:

 pthread_t gTid;

pthread_attr_t gAttr;

int gExitThread = 0;
  

Я создаю дочерний поток из своего основного потока выполнения:

 err = pthread_attr_init(amp;gAttr);
if (err)
{
    throw CONTROLLER_THREAD_ERROR;
}

err = pthread_attr_setdetachstate(amp;gAttr, PTHREAD_CREATE_JOINABLE);
if (err)
{
    throw CONTROLLER_THREAD_ERROR;
}

err = pthread_create(amp;gTid,amp;gAttr,threadHandler,NULL);
if (err)
{
    throw CONTROLLER_THREAD_ERROR;
}
  

Внутри «threadHandler» у меня есть следующий цикл выполнения с использованием API core foundation:

 // Enter run loop
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, RUN_LOOP_TIMEOUT, false);
while (result == kCFRunLoopRunTimedOut)
{
    if (gExitThread) break;
    result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, RUN_LOOP_TIMEOUT, false);
}
  

Глобальная переменная gExitThread используется для сигнализации о том, что поток должен корректно завершить
себя. Макрос RUN_LOOP_TIMEOUT установлен на 2 секунды (хотя большие и меньшие значения не имеют значения).

Следующий фрагмент кода в основном потоке сигнализирует о завершении потока:

 int err = 0;
void* exitValue = NULL;

printf("Stopping controller thread...n");

gExitThread = 1;
err = pthread_join(gTid, amp;exitValue);
if (err)
{
    displayError2(err);
    throw CONTROLLER_THREAD_ERROR;
}

err = pthread_attr_destroy(amp;gAttr);
if (err)
{
    throw CONTROLLER_THREAD_ERROR;
}
  

Вызов ‘pthread_join’ вылетает из-за ошибки сегментации после небольшой задержки. Я также заметил, что замена вызова ‘pthread_join’ на обычный режим ожидания, скажем, на две секунды, вызывает точно такую же ошибку сегментации при выполнении ‘usleep (2000000)’!
Я скопирую обратную трассировку дампа ядра ниже как для ‘pthread_join’, так и для ‘usleep’.

pthread_join:

 #0  0x00007fff8343aa6a in __semwait_signal ()
#1  0x00007fff83461896 in pthread_join ()
#2  0x000000010000179d in Controller::cleanup () at src/native/osx/controllers.cpp:335
#3  0x0000000100008e51 in ControllersTest::performTest (this=0x100211bf0) at unittests/src/controllers_test.cpp:70
#4  0x000000010000e5b9 in main (argc=2, argv=0x7fff5fbff980) at unittests/src/verify.cpp:34
  

usleep(2000000):

 #0  0x00007fff8343aa6a in __semwait_signal ()
#1  0x00007fff8343a8f9 in nanosleep ()
#2  0x00007fff8343a863 in usleep ()
#3  0x000000010000177b in Controller::cleanup () at src/native/osx/controllers.cpp:335
#4  0x0000000100008e3d in ControllersTest::performTest (this=0x100211bf0) at unittests/src/controllers_test.cpp:70
#5  0x000000010000e5a5 in main (argc=2, argv=0x7fff5fbff980) at unittests/src/verify.cpp:34
  

Любая помощь будет принята с благодарностью.

Ответ №1:

Кажется, что код после вашего цикла while внутри threadHandler вызывает ошибку segfault. Если внутри потока генерируется сигнал (например, SIGSEGV), сам процесс будет остановлен.

Попробуйте использовать GDB и thread apply all bt , чтобы получить обратную трассировку для всех потоков.

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

1. Спасибо тебе, Милан. Это было именно так! Оказывается, в моем потоке я приводил нулевой указатель на тип класса, а затем он зависал при доступе к элементам данных этого экземпляра. Это не только исправлено, я знаю немного больше о потоках и gdb 🙂