作为更大的线程调度 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/