另一方面,Windows不记录甚至不保证系统调用机制的一致性.在Windows上进行系统调用的唯一方法是调用从CRT完成的ntdll.dll(或者其他一些* .dll),因此涉及两个函数调用.如果静态使用CRT并且函数内联(在Windows上比Linux稍微常见),我们仍然可以对ntdll.dll进行单一函数调用,这是我们无法解决的.
因此,在我看来理论上,Windows上的系统调用本身就会变慢,因为它们总是要比Linux等效函数执行一次函数调用.这种理解(以及我上面的解释)是否正确?
注意:我纯粹在理论上问这个问题.我理解在进行系统调用时(我认为总是涉及2个上下文切换 – 每个方向一个),额外函数调用的成本可能完全可以忽略不计.
>使用int / iret指令
>使用sysenter / sysexit说明
基于纯int / iret的系统调用需要211个cpu周期(现代处理器甚至更多). Sysenter / sysexit需要46个cpu滴答.正如您所看到的,只有一对用于系统调用的指令的执行会带来很大的开销.但是任何系统调用实现都涉及内核方面的一些工作(内核上下文的设置,调用的调度及其参数等).对于基于int / iret和sysenter / sysexit的系统调用,或多或少现实的高度优化的系统调用将花费约250和~100个cpu周期.在Linux和Windows中,它需要大约500个滴答.
同时,函数调用(基于call / ret)每个参数的成本为2-4 tics 1.
如您所见,函数调用引入的开销与系统调用成本的比较可以忽略不计.
另一方面,如果在应用程序中嵌入原始系统调用,则会使其高度依赖硬件.例如,如果没有这些指令支持的基于sysenter / sysexit的原始系统调用的应用程序将在旧PC上执行,该怎么办?此外,您的应用程序将对OS使用的系统调用约定敏感.
通常使用诸如ntdll.dll和glibc之类的库,因为它们为系统服务提供了众所周知的和硬件独立的接口,并隐藏了与场景后面的内核通信的细节.
如果使用相同的方式跨越用户/内核空间边界,Linux和Windows的系统调用成本大致相同(差异可以忽略不计).两者都尝试在每台特定机器上使用最快的方式.至少从Windows XP开始的所有现代Windows版本都是为sysenter / sysexit准备的.一些旧的和/或特定版本的Linux仍然可以使用基于int / iret的调用. x64版本的操作系统依赖于syscall / sysret指令,这些指令的作用类似于sysenter / sysexit,可作为AMD64指令集的一部分使用.