在 C 中使用 jmp_buf 数组进行线程处理(在 xv6 中测试)

问题描述 投票:0回答:1

你们有没有尝试过将一堆jmp_buf放在一起并按顺序触发它?

我试图使用 jmp_buf 数组来调度线程。下面是一个简单的例子。 我在 xv6 中运行并编译此代码并收到如图所示的错误。

我期待这样的输出:

3 2 1

这是我的代码:

struct threads{
    jmp_buf env;
};
int main(){
    struct threads **t = (struct threads**) malloc(sizeof(struct threads*)*3);
    for (int i = 0; i < 3; i++){
        if (setjmp(t[i]->env)!=0){
            printf("%d \n",i);
            if (i+1<3) longjmp(t[i+1]->env,-1);
        }
    }
    longjmp(t[0]->env,-1);
    return 0;
}

错误:

c multithreading operating-system riscv xv6
1个回答
0
投票

你们有没有尝试过...

是的。早在 20 世纪 80 年代的某个时候,我就这么做了。它更像是一个概念证明。我从未在任何实际项目中使用过它。

我当时所做的一切在今天都被称为“未定义的行为”,但当时,一切如常进行实验,阅读库和/或操作系统源代码,并找出在给定的工具链上什么可以工作。给定平台。


埃里克·波斯特皮斯基尔说,

...函数本地自动对象的值是不确定的。

这并不难处理。我自制的线程库中的 setjmp 和 longjmp 调用位于编写的函数内部,以便不依赖于上下文切换中幸存的任何局部变量的值。 调用库的客户端函数不必担心它,因为客户端函数永远不必担心它们的局部变量被任何任意函数调用破坏。


池上说,

...每个线程都需要一个堆栈。因此,除了更改指令指针之外,您还需要一些可以交换堆栈的东西。

这有点误导。 “交换堆栈”意味着更改堆栈指针。

longjmp
就是这样做的。怎么可能不呢?当按预期使用时,它必须恢复同一堆栈中某些函数调用的上下文。如果不恢复保存的堆栈指针,它就无法做到这一点。我的库使用它来恢复从不同堆栈中保存的某些函数调用的上下文。

但是,每个线程都必须有自己的堆栈,并且在每个线程堆栈的底部,必须有某个函数的激活记录,就好像该函数是从某个地方调用的,但又是从哪里调用的?

我的库的“创建新线程”函数分配了一块内存用作堆栈,然后它人为地合成一个要调用的第一个函数的堆栈帧,并且它人为地合成了一个

jmp_buf
包含“保存”的上下文,这样每当程序
longjmp()
编辑到新堆栈时,函数的第一条指令就会在新堆栈上执行。


就像我说的,以上都是UB。你不能“依赖”它来与任何给定的编译器、任何给定的运行时库、任何给定的操作系统或硬件一起工作,在多 CPU 主机上执行它可能比我当时做的时候更棘手. 但是你可以尝试一下。即使你失败了,你也可能会学到一些东西。

© www.soinside.com 2019 - 2024. All rights reserved.