c - ucontext.h 和 uc_link 没有从主线程返回

标签 c

作为更大的线程调度 api 的一部分,这是我想做的事情。

我想创建一个线程,当主线程(创建线程的线程)退出时,我刚创建的线程应该执行。我正在尝试使用 ucontext 和 uc_link 执行此操作,但它不起作用。当我尝试为当前线程设置 uc_link 时,它似乎不起作用。

这是此链接中的一个稍微修改过的示例,这是我厌倦了完成这项工作的原因。

http://pubs.opengroup.org/onlinepubs/009695399/functions/makecontext.html

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


static ucontext_t ctx[3];


static void
f1 (void)
{
    puts("start f1");
    swapcontext(&ctx[1], &ctx[2]);
    puts("finish f1");
}


static void
f2 (void)
{
    puts("start f2");
    swapcontext(&ctx[2], &ctx[1]);
    puts("finish f2");
}


int
main (void)
{
    char st1[8192];
    char st2[8192];


    getcontext(&ctx[1]);
    ctx[1].uc_stack.ss_sp = st1;
    ctx[1].uc_stack.ss_size = sizeof st1;
    ctx[1].uc_link = 0;
    makecontext(&ctx[1], f1, 0);


    getcontext(&ctx[2]);
    ctx[2].uc_stack.ss_sp = st2;
    ctx[2].uc_stack.ss_size = sizeof st2;
    ctx[2].uc_link = &ctx[1];
    makecontext(&ctx[2], f2, 0);

    getcontext(&ctx[0]);
    ctx[0].uc_link = &ctx[2];
    return 0;
}

预期输出:

finished main
start f2
start f1
finish f2
finish f1

给定输出:

finished main

如何以有意义的方式为当前线程/进程设置 uc_link?

最佳答案

用以下代码替换上面代码中的 main 会产生预期的输出。

int
main (void)
{
    char st1[8192];
    char st2[8192];

    getcontext(&ctx[1]);
    ctx[1].uc_stack.ss_sp = st1;
    ctx[1].uc_stack.ss_size = sizeof st1;
    ctx[1].uc_link = &ctx[0];
    makecontext(&ctx[1], f1, 0);

    getcontext(&ctx[2]);
    ctx[2].uc_stack.ss_sp = st2;
    ctx[2].uc_stack.ss_size = sizeof st2;
    ctx[2].uc_link = &ctx[1];
    makecontext(&ctx[2], f2, 0);

    getcontext(&ctx[0]);
    ctx[0].uc_mcontext.gregs[16] += 0x26;
    puts("finish main");
    setcontext(&ctx[2]);
    return 0;
}

但是这并没有按照您说的去做。

上下文函数是一种将特定返回地址放入堆栈的方法。

  • getcontext 将下一条指令的地址捕获到结构中
  • makecontext 将结构中的地址更改为其函数参数的地址
  • setcontext/swapcontext 将结构体中的地址放到栈上并返回给它

上面这个程序只有一个控制线程。我认为您确实需要多个线程,在这种情况下您不会使用这些上下文函数。

有关堆栈和 C 调用约定的更多信息,Eli Bendersky 有两篇带图表的好文章:

FWIW,为了获得上面代码中的 0x26 常量,我不得不反汇编 main 以找到 setcontext 调用后的第一个地址。

关于c - ucontext.h 和 uc_link 没有从主线程返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35047816/

相关文章:

c - c 中的 null 类型和编译器错误

c - 汉诺塔 - 迭代,使用列表

linux中的C用户名——获取当前用户名

c - 链表-基本插入函数

c - 平均字长 [C]

c - 如何在 Rust 中表示指向 C 数组的指针?

c - while 循环在输入错误后一直忽略 scanf

c - movq 指令出现段错误?

c - 如何在 C 中将 char 连接到 char*?

c - 从目录中逐一读取文件