Ошибка сегментации с ucontext makecontext на OS X 10.10
#include <stdio.h>
#include <stdlib.h>
#define _XOPEN_SOURCE 600
#include <ucontext.h>
/* Tests creation.
Should print "Hello World!" */
typedef struct thread_t{
ucontext_t thread_context;
}thread_t;
void *thr1(void *in) {
printf("Hello World!\n");
fflush(stdout);
return NULL;
}
void *thr2(void *in) {
printf("goodbye World!\n");
fflush(stdout);
return NULL;
}
int main() {
thread_t t1;
thread_t t2;
thread_create( &t1, thr1, NULL);
// if you comment out the following line, the program will run like a charm.
thread_create( &t2, thr2, NULL);
setcontext(&t1.thread_context);
return EXIT_SUCCESS;
}
void thread_routine(void *(*start_routine)(void *), void *arg)
{
start_routine(arg);
printf("gtthread routine finished\n");
}
int thread_create(thread_t *thread,
void *(*start_routine)(void *),
void *arg){
if (getcontext(&(thread->thread_context)) == -1)
{
perror("getcontext");
}
thread->thread_context.uc_stack.ss_sp = (char*) malloc(SIGSTKSZ);
thread->thread_context.uc_stack.ss_size = SIGSTKSZ;
thread->thread_context.uc_link = NULL;
makecontext(&(thread->thread_context), thread_routine, 2, (void *)start_routine, arg);
}
Я запускаю свой код в OS X 10.10 с gcc. Я пытаюсь реализовать библиотеку usercontext.
Если я закомментирую thread_create( &t2, thr2, NULL);
код даст желаемый эффект. Я понятия не имею, почему линия, связанная с t2
приведет к ошибке сегментации t1
,
Авторские заметки
Я с радостью работаю над реализацией библиотеки usercontext после перехода на Ubuntu. Все отлично работает Нет ошибки сегментации больше. И, как и ожидалось, он падает на OS X 10.10.
Я полагаю, что поскольку makecontext(), swapcontext() и т. Д. Устарели в OS X начиная с 10.6, как предупреждено компилятором, я не должен ожидать, что он будет работать.
2 ответа
У вашей программы есть некоторые недостатки, некоторые из которых приводят к неопределенному поведению. Неопределенное поведение может проявиться именно так, как вы ожидали, но если это произойдет один раз, в какой-то конкретной среде, это не дает никаких оснований ожидать, что это произойдет снова - не в этой среде, и конечно, не в другой среде.
Вот более серьезные проблемы, которые я заметил:
thread_routine()
не имеет правильного возвращаемого типа или типов аргументов для функции запуска контекста. Ожидается, что функция запуска контекста вернетvoid
(т.е. ничего) нетvoid *
, что совсем другое. Также фактические аргументы, переданные ему, если таковые имеются, будут все типомint
, Поэтому, когда эта функция вызывается вашей программой в результатеsetcontext()
, неопределенные результаты поведения. На машине, где указатели функций и указатели объектов имеют одинаковый размерint
Вы можете сойти с рук, но на других машинах программа, скорее всего, потерпит крах. Это, вероятно, причина сегфоута, который вы наблюдали.В
thread_create()
вы инициализируетеthread->thread_context.uc_link
вNULL
, Само по себе это не ошибка, но в более широком смысле это приведет к тому, что когда функция запуска контекста вернется, поток (OS), в котором он запущен, завершится. Предположительно, вы бы предпочли иметь возможность поменяться в другом контексте.Ты используешь
setcontext()
переключиться наt1
контекст. В случае успеха этот вызов не будет возвращен ни тогда, ни позже, и у вас не будет возможности позже переключиться наt2
контекст. На практике, тем не менее, поток и, следовательно, вся программа завершатся в любом случае, когда функция запуска t1 вернется (см. Выше), так что это спорный вопрос для вас. Для чего это стоит, хотя, вы, вероятно, должны использоватьswapcontext()
вместо.thread_create()
объявлено о возвращенииint
, но это не имеетreturn
заявление.
gcc
кстати, должно быть предупреждение о некоторых из этих проблем. Если нет, то увеличьте уровень предупреждения. -Wall
уровень должен быть достаточным, но я часто включаю -Wextra
а также для поиска вопросов. Иногда есть предупреждения, которые вы можете игнорировать (особенно с -Wextra
), но вы должны сделать эту оценку отдельно для каждого.
Я думаю, что вы поставили "thread.h", почему вы используете потоки, если вы можете попробовать это