C++ - Sleep()和cin如何工作?

17

只是好奇,Sleep() 函数(在 windows.h 中声明)实际上是如何工作的?也许不仅限于该实现,可以是任何一个。我的意思是 - 它是如何实现的?它如何能够让代码“停止”一段时间?还好奇 cin >> 等函数是如何工作的。它们到底做了些什么?

我所知道的唯一一种阻止某些代码继续运行的方法是使用 while 循环,但考虑到当您调用从 stdin 读取数据的方法时所发生的情况(只需比较 while(true) 和从 stdin 读取数据的处理能力即可),我猜测它们并不是这样工作的。

7个回答

29
操作系统使用称为调度器的机制来保持其管理的所有线程或进程之间的良好行为。每秒钟,计算机的硬件时钟会打断 CPU,导致操作系统的调度器被激活。然后,调度器将查看所有试图运行的进程,并决定哪个进程可以在下一个时间片运行。它用于决定的不同因素取决于每个进程的状态以及它之前使用的时间量。因此,如果当前进程一直在繁重地使用 CPU,阻止其他进程取得进展,那么调度器会使当前进程等待并切换到另一个进程,以便它可以做一些工作。
但更多情况下,大多数进程都处于等待状态。例如,如果一个进程正在等待从控制台输入,操作系统可以查看该进程的信息并查看它正在等待的 IO 端口。它可以检查这些端口以查看它们是否有数据供进程处理。如果有数据,它就可以重新启动该进程,但如果没有数据,则该进程会被跳过当前的时间片。
至于 sleep(),任何进程都可以通知操作系统,它想要等待一段时间。调度器将在硬件中断之前被激活(这也是当进程尝试从没有准备好读取数据的流中进行阻塞读取时发生的情况),并且操作系统会记录该进程正在等待什么。对于睡眠,该进程正在等待闹钟响起,或者它每次重新启动时都会再次让步,直到计时器结束。
由于操作系统只在某些东西导致它抢占正在运行的进程后才恢复进程,例如进程让步或硬件定时器中断,因此 sleep() 不太准确,其精度取决于操作系统或硬件,但通常在一毫秒或更多左右。如果需要更高的精度或非常短的等待,唯一的选择是使用您提到的繁忙循环构造。

3
操作系统负责调度进程的运行(哪些进程有资格运行,以什么顺序运行...)。 Sleep() 可能会发出一个系统调用,告诉内核“不要让我使用处理器 x 毫秒”。

只是好奇,你自己如何进行这样的调用?如果在Windows上由于隐藏实现而无法进行,也许可以提供一个Linux示例? - quano
GNU/Linux符合Posix系统调用。Posix系统调用被指定为C函数,但通常它们只是底层系统调用的包装器。如果您查看/usr/include/asm/unistd_32.h,您会发现有一个nanosleep()系统调用。很可能sleep()是通过调用这个系统调用来实现的。在Windows上也有系统调用,但它们是未记录的,所以几乎没有理由去了解它们的工作原理。 - Bastien Léonard

2
简单来说,Sleep()函数告诉操作系统暂时忽略该进程/线程。

1

'cin'使用了大量的重载运算符。'>>'通常是右位移,但在C++中,它被重载为几乎每种类型的右操作数。为每个类型提供了一个单独的函数,它从控制台读取并将输入转换为您给定的变量类型。例如:

std::cin::operator>> (int &rhs);

这不是真正的C++ - 我已经有一段时间没有使用流和重载了,所以我不记得返回类型或参数的确切顺序。尽管如此,当您运行cin >>整数变量时,将调用此函数。

确切的底层实现取决于操作系统。


0
答案取决于操作系统,但一般来说,操作系统要么调度其他代码在另一个线程中运行,要么如果它真的没有任何事情可做,就让CPU等待直到硬件事件发生,这会导致CPU跳转到某个称为中断处理程序的代码,然后可以决定运行哪些代码。

0
如果你正在寻找一种更加可控的阻塞多线程程序中的线程/进程的方式,那么可以看看信号量、互斥锁、关键段和事件。这些都是用来阻塞进程或线程的技术(而不是通过 while 结构来占用 CPU)。
它们本质上是基于等待/信号范式工作的,其中被阻塞的线程正在等待另一个进程发出信号告诉它再次开始。这些技术(至少在Windows中)还可以具有超时功能,因此提供了类似于Sleep()的功能。

超时版本也可在POSIX系统上使用。 - SingleNegationElimination

0

在低级别上,系统有一个名为“调度程序”的例程,将所有正在运行的程序的指令分派到实际运行它们的CPU(s)。像“Sleep”和“usleep”这样的系统调用匹配到告诉调度程序忽略该线程或进程一定时间的指令。

至于C++流,"cin"隐藏了实际的文件句柄(stdin和stdout实际上就是这样的句柄),而">>"操作符则隐藏了底层的读写调用。由于它是一个接口,所以实现可能是特定于操作系统的,但从概念上讲,它仍然在幕后执行类似printf和scanf的操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接