现在有点晚了,但我自己对这种话题很感兴趣。事实上,除了并行化/性能之外,没有什么特别需要内核干预的线程。
强制 BLUF:
Q1:不需要。至少需要初始系统调用才能跨各种 CPU 内核/超线程创建多个内核线程。
Q2:视情况而定。如果您创建/销毁执行微小操作的线程,那么您就是在浪费资源(线程创建过程将大大超过踏板在退出之前使用的时间)。如果您创建 N 个线程(其中 N 是系统上的 ~# of cores/hyper-threads)并重新分配它们,那么答案可能是肯定的,具体取决于您的实现。
Q3:如果您提前知道精确的操作排序方法,您可以优化操作。具体来说,您可以创建相当于 ROP 链的内容(或前向调用链,但这实际上可能最终实现起来更复杂)。这个 ROP 链(由线程执行)将连续执行“ret”指令(到它自己的堆栈),其中该堆栈被连续添加(或在它滚动到开头的情况下添加)。在这样一个(奇怪的!)模型中,调度程序保留一个指向每个线程的“ROP 链末端”的指针,并向其写入新值,从而代码在内存中循环执行函数代码,最终导致 ret 指令。同样,这是一个奇怪的模型,但仍然很有趣。
在我价值 2 美分的内容上。
我最近通过管理各种堆栈区域(通过 mmap 创建)并维护一个专用区域来存储“线程”的控制/个性化信息,创建了在纯汇编中有效地作为线程运行的东西。尽管我没有这样设计,但可以通过 mmap 创建一个大块内存,我将其细分为每个线程的“私有”区域。因此,只需要一个系统调用(尽管它们之间的保护页面很聪明,但它们需要额外的系统调用)。
此实现仅使用进程产生时创建的基本内核线程,并且在整个程序执行过程中只有一个用户模式线程。程序通过内部控制结构更新自己的状态并自行安排。I/O 等在可能的情况下通过阻塞选项处理(以降低复杂性),但这不是严格要求的。当然,我使用了互斥锁和信号量。
要实现这个系统(完全在用户空间中,如果需要也可以通过非 root 访问),需要以下内容:
线程归结为的概念: 堆栈操作的堆栈(有点自我解释和明显) 一组要执行的指令(也很明显) 一小块内存,用于保存单个寄存器内容
调度程序归结为:调度程序指定的有序列表(通常是优先级)中一系列线程的管理器(请注意,进程从不实际执行,只是它们的线程执行)。
线程上下文切换器:注入到代码的各个部分(我通常将它们放在重型函数的末尾)的宏,大致相当于“线程屈服”,它保存线程的状态并加载另一个线程的状态。
因此,确实有可能(完全在汇编中并且除了初始 mmap 和 mprotect 之外没有系统调用)在非根进程中创建用户模式线程状构造。
我只添加了这个答案,因为您特别提到了 x86 程序集,而这个答案完全是通过一个完全用 x86 程序集编写的自包含程序得出的,该程序实现了最小化系统调用和最小化系统端线程的目标(减去多核功能)高架。