在Linux x86 GAS程序集中是否可以创建没有系统调用的线程?

在学习“汇编语言”(在Linux架构中,使用GNU作为汇编程序的x86架构)时,其中一个瞬间就是使用系统调用的可能性。 这些系统调用非常方便,有时甚至是必要的,因为您的程序在用户空间中运行。
然而,系统调用在性能方面相当昂贵,因为它们需要中断(当然还有系统调用),这意味着上下文切换必须从用户空间中的当前活动程序切换到内核空间中运行的系统。

我想说的是:我目前正在实现一个编译器(用于大学项目),我想添加的一个额外功能是支持多线程代码,以提高编译的程序的性能。 因为一些多线程代码将由编译器自动生成,所以这几乎可以保证在其中会有真正的微小的多线程代码。 为了赢得一场胜利,我必须确定使用线程会使这种情况发生。

然而,我的恐惧是,为了使用线程,我必须进行系统调用和必要的中断。 微小的(自动生成的)线程因此会受到进行这些系统调用所花费的时间的高度影响,甚至可能导致性能下降。

因此我的问题是双重的(在它下面有一个额外的奖励问题):

  • 是否可以编写汇编代码,可以同时在多个内核上同时运行多个线程,而无需系统调用?
  • 如果我有非常小的线程(线程总执行时间很小),性能下降,还是不值得花费精力,我会获得性能提升吗?
  • 我的猜测是,没有系统调用,多线程汇编代码是不可能的。 即使情况如此,你是否有建议(甚至更好:一些真实的代码)尽可能高效地实现线程?


    简短的答案是,你不能。 当您编写汇编代码时,它会在一个且只有一个逻辑(即硬件)线程上按顺序运行(或使用分支)。 如果你想要在另一个逻辑线程上执行一些代码(无论是在同一个内核上,在同一个CPU的不同内核上,还是在不同的CPU上),你需要让OS设置另一个线程的指令指针( CS:EIP )指向您想要运行的代码。 这意味着使用系统调用来让操作系统做你想做的事情。

    用户线程不会为您提供所需的线程支持,因为它们都运行在相同的硬件线程上。

    编辑:将 Ira Baxter的答案与Parlanse结合在一起。 如果你确保你的程序在每个逻辑线程中都有一个线程开始运行,那么你可以建立你自己的调度程序而不依赖于操作系统。 无论哪种方式,您都需要一个调度程序来处理从一个线程跳到另一个线程。 在调度程序的调用之间,没有特殊的汇编指令来处理多线程。 调度程序本身不能依赖任何特殊的程序集,而是依赖于每个线程中调度程序各部分之间的约定。

    无论哪种方式,无论您是否使用操作系统,您仍然必须依靠某个调度程序来处理跨线程执行。


    “医生,医生,当我这样做的时候会很痛苦”。 医生:“不要那样做”。

    简而言之,您可以在不调用昂贵的操作系统任务管理原语的情况下进行多线程编程。 简单地忽略线程调度操作的操作系统。 这意味着你必须编写自己的线程调度器,并且不要将控制权交还给操作系统。 (你必须更聪明地了解你的线程开销,而不是相当聪明的操作系统人员)。 我们之所以选择这种方法,是因为窗口进程/线程/光纤调用对于支持几百条指令的计算颗粒来说太昂贵了。

    我们的PARLANSE编程语言是一种并行编程语言:请参见http://www.semdesigns.com/Products/Parlanse/index.html

    PARLANSE在Windows下运行,提供并行的“谷物”作为抽象的并行构造,并且通过高度调整的手写调度器和由PARLANSE编译器生成的调度代码的组合调度这些谷物,考虑谷物的上下文以最小化调度高架。 例如,编译器确保在可能需要调度(例如,“等待”)的点处谷物的寄存器不包含信息,并且因此调度程序代码仅需要保存PC和SP。 事实上,调度程序代码通常不会得到控制; 分叉的谷物只存储分叉的PC和SP,切换到编译器预分配的堆栈并跳转到谷物代码。 谷物的完成将重新启动叉子。

    通常有一个同步谷物的互锁,由编译器使用原生LOCK DEC指令实现,这些指令实现了相当于计算信号量的数量。 应用程序可以逻辑分岔数百万颗谷物; 如果工作队列足够长时间,调度程序会限制母公司生成更多的工作,所以更多的工作不会有所帮助。 调度程序执行工作窃取以允许工作不足的CPU从相邻CPU工作队列中抓取已准备好的粒子。 这已经被实现以处理多达32个CPU; 但是我们有点担心x86供应商可能会在未来几年实际使用这些产品!

    PARLANSE是一种成熟的语言; 我们自1997年以来一直在使用它,并已在其中实施了数百万行的并行应用程序。


    实现用户模式线程。

    历史上,线程化模型被推广为N:M,即在M个内核模型线程上运行的N个用户模式线程。 现代用途是1:1,但并不总是这样,它不一定是这样。

    您可以自由地在单个内核线程中维护任意数量的用户模式线程。 这只是你的责任,经常在它们之间切换,看起来并发。 你的线索当然是合作而不是先发制人的; 您基本上将yield()调用分散到您自己的代码中,以确保发生常规切换。

    链接地址: http://www.djcxy.com/p/82351.html

    上一篇: Is it possible to create threads without system calls in Linux x86 GAS assembly?

    下一篇: Heap corruption detection with Windows GFlags application