Реинверсия управления с использованием longjmp
Я пытаюсь реализовать реинверсию управления в c с помощью longjmp, в настоящее время у меня есть этот код:
#include <stdio.h>
#include <setjmp.h>
jmp_buf env;
int arg;
typedef void (*fptr)(int);
fptr callback;
void cb(int a)
{
arg = a;
longjmp(env, 1);
}
#define cont1(f, x) do { if(!setjmp(env)) { f(x, &cb); return; } } while(0)
void callback_func(int num, fptr cb)
{
printf("in a func, num = %d\n", num);
callback = cb;
}
void task1()
{
printf("before continuation\n");
cont1(callback_func, 7);
printf("after continuation\n");
}
void task2()
{
printf("in thread 2\n");
(*callback)(5);
}
int main()
{
task1();
task2();
printf("arg = %d\n", arg);
return 0;
}
И мой вопрос: не вызывает ли это неопределенное поведение или может вызвать какие-либо проблемы при использовании в реальном мире, и если да, то есть ли лучший способ сделать это?
1 ответ
Эта программа имеет неопределенное поведение. См. C11 7.13.2.1 Функция longjmp (выделено мной):
Если такого вызова не было, или если вызов был из другого потока выполнения, или если функция, содержащая вызов макроса setjmp, прекратила выполнение248 за это время, или если вызов макроса setjmp находился в области видимости идентификатора с переменно измененным типом и выполнением оставил эту область в промежутке, поведение не определено.
248) Например, путем выполнения оператора return или потому, что другой вызов longjmp вызвал переход к вызову setjmp в функции ранее в наборе вложенных вызовов.
В то время, когда вы cb
звонки longjmp
, функция, которая вызвала setjmp
заполнять env
, task1
, вернулся. Так зовет longjmp
не определено
Язык C не имеет средств для выполнения того, что вы пытаетесь сделать, за исключением (теперь с C11) потоков, использующих условные переменные для управления тем, какой поток выполняется.