【问题标题】:reinversion of control using longjmp使用 longjmp 重新反转控制
【发布时间】:2015-09-17 15:13:25
【问题描述】:

我正在尝试使用 longjmp 在 c 中实现控制反转,目前我有这个代码:

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

我的问题是:这不会引发未定义的行为或可能导致实际使用中的任何问题,如果是,那么有没有更好的方法来做到这一点?

【问题讨论】:

  • 肯定有办法写出比这个更清晰的代码,但是为什么你认为它会出现导致UB的错误呢?或许您可以先给我们分析一下什么是对的,什么是错的?
  • 据我了解,控制权的重新反转依赖于延续,或类似的东西。尽管使用setjmp() / longjmp() 与延续有一些相似之处,但它不是等价的。我不认为 C 或其标准库有等价物。
  • @JohnBollinger:这是正确的。但是你可以使用线程构造类似的东西。

标签: c inversion-of-control undefined-behavior setjmp


【解决方案1】:

此程序具有未定义的行为。请参阅 C11 7.13.2.1 longjmp 函数(强调我的):

如果没有这样的调用,或者如果调用来自另一个执行线程,或者如果包含 setjmp 宏调用的函数在此期间终止了执行248,或者如果 setjmp 宏的调用在具有可变修改类型的标识符的范围内,并且执行在此期间离开了该范围,则 行为未定义

248) 例如,通过执行 return 语句 或因为另一个 longjmp 调用已导致转移到嵌套调用集中较早的函数中的 setjmp 调用。

当您cb 调用longjmp 时,调用setjmp 填充envtask1 的函数已经返回。因此调用longjmp 是未定义的。

C 语言没有办法做你想做的事,除了(现在是 C11)线程,使用条件变量来控制哪个线程运行。

【讨论】:

  • 好吧,但是来自另一个线程的longjmp 也是未定义的行为,那么如何在不违反此规则的情况下使用线程来实现呢?
  • 你不会从另一个线程longjmp。您只需使用 condvars 根据您想要“转移控制”的代码来启动/停止线程。
猜你喜欢
  • 2015-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-30
  • 1970-01-01
  • 2010-09-20
  • 2020-07-31
  • 1970-01-01
相关资源
最近更新 更多