2

getcontext可以多次返回。例如,我绘制了一个类似于此处演示的 C 程序:

#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <ucontext.h>

struct communication {
        const ucontext_t *return_ctx;
        int return_value;
};

static void
test(ucontext_t *thisctx, struct communication *comm)
{
        int i = 0;
        assert(getcontext(thisctx) == 0);
        // getcontext will return 3 times with i having different values

        comm->return_value = ++i;
        setcontext(comm->return_ctx);
        assert(0);
}

int
main(void)
{
        ucontext_t mainctx, testctx;
        struct communication comm;
        char test_stack[SIGSTKSZ];

        assert(getcontext(&testctx) == 0);
        testctx.uc_stack.ss_sp = test_stack;
        testctx.uc_stack.ss_size = sizeof test_stack;
        makecontext(&testctx, test, 2,
                &testctx, &comm);

        for (int i = 0; i < 3; ++i) {
                // Rewind test's execution where 'getcontext' returns
                comm.return_ctx = &mainctx;
                assert(swapcontext(&mainctx, &testctx) == 0);
                assert(printf("%d\n", comm.return_value) > 0);
        }

        return 0;
}

编译并运行它

$ gcc -std=gnu99 -O3 -o getcontext_test getcontext_test.c
$ ./getcontext_test
1
1
1

没有给出预期1 2 3,因为编译器认为只有在分配给时i才能相等。1comm->return_value

我可以通过定义i volatile来解决这个问题,但是我想要一个更规范的方法来解决这个问题。

4

1 回答 1

2

对您想要的东西的必要(但可能还不够)要求i(在test函数中;不幸的是,您要询问的标识符的函数之间的名称重复是不幸的)volatile。这已经是标准中的要求(7.13.2.1 ¶3):

所有可访问对象都有值,并且抽象机的所有其他组件都有状态,截至调用 longjmp 函数时,除了包含调用相应 setjmp 的函数的本地自动存储持续时间的对象的值没有 volatile 限定类型并且在 setjmp 调用和 longjmp 调用之间发生更改的宏是不确定的。

对于可能在连续返回之间修改的对象setjmp,因此您应该(并且应该必须)对 . 执行相同的操作非常有意义getcontext

由于其他原因,编译器可能需要知道getcontext返回不止一次。在 GCC 和兼容的编译器(除了 MSVC 之外的大多数编译器)上,您可以使用__attribute__((__returns_twice__)). 但是,如果需要,声明的头文件getcontext(或编译器内部)应该已经在做类似的事情了。

于 2018-11-01T15:06:08.713 回答