8

我有一个关于终端和进程如何工作的一般性问题。

在任何进程中,如果我写入标准输出(即文件描述符 2),它就会被绘制在终端窗口上。我的问题是,这实际上是如何实现的?stdout 是否是终端不断读取并在屏幕上绘制内容的实际“虚拟”文件?或者进程/标准输出流和终端之间是否存在某种 IPC?

请注意,当我说终端时,我指的是一些通用的 GUI 终端/控制台,例如 Mac 上的终端。

PS如果这个问题不清楚,请告诉我,我会很乐意再次解释:)

谢谢!

4

3 回答 3

5

The magic part here that you don't seem to be aware of is the kernel's tty layer.

Each terminal window you open corresponds to a pseudoterminal device — for instance, /dev/ttys001 is a name for one such device on Mac OS X. By default, any process that's running in a terminal and which doesn't have its input/output redirected from/to somewhere else, its standard input, output, and error are all set to one of these devices. For instance, if I run lsof on a cat process running in a terminal, I see:

COMMAND   PID USER   FD   TYPE DEVICE  SIZE/OFF     NODE NAME
...
cat     52919 user    0u   CHR   16,5    0t4562     3313 /dev/ttys005
cat     52919 user    1u   CHR   16,5    0t4562     3313 /dev/ttys005
cat     52919 user    2u   CHR   16,5    0t4562     3313 /dev/ttys005

When a process writes to a pseudoterminal slave device, the output is routed to the process holding the master end of the connection (in this case, your terminal application), which can read it. Similarly, when a terminal application writes to a pseudoterminal master device, the data becomes available to any process that's reading from the corresponding slave device.

There are a few other tricks involved with pseudoterminal devices. Most notably, they have an inherent size in rows and columns, which an application running in them can query, they can perform certain simple translations on data passing through them (for instance, CR to CR/LF, backspace to DEL, and other such things), and they can generate signals when certain characters are seen (e.g, Ctrl-C generates an interrupt signal to the foreground process). There's a lot of weird historical subtleties here, but the point is that the kernel's tty layer is where most of this behavior exists.

Pseudoterminal devices are created using the forkpty() libc function. The details of how this works behind the scenes vary from platform to platform, and can get pretty hairy, so I won't dig into the details.

于 2013-04-11T00:32:46.350 回答
4

当您包含 stdio.h 时,stdout 是在那里定义的变量。

引用维基百科

stdout - 指向标准输出流的 FILE 的指针,通常是显示终端

而且,正如 Russ C 所提到的,在 Unix 中一切都是文件,所以在这方面你是对的。

显然,每个打开的 unix 程序都有其输出、输入和错误流,默认情况下分别设置为 stdout、stdin 和 stderr。不过,它们可以更改。就像在终端中使用'<'重定向文件的标准输入一样,你可能会在如下语句中执行此操作

mysql -u root -p dbname < ./data.sql

我想这并不能真正回答你关于实现的真正细节的所有问题,但知道它是一个文件流可能会让你对正在发生的事情有一个很好的了解。

于 2013-04-10T23:56:07.100 回答
2

这是大图。

  1. 终端是一个设备。它是一个硬件,你可以通过向它的硬件接口写入数据来让事物出现在它上面。
  2. 操作系统将此(以及任何硬件设备)的处理委托给设备驱动程序。设备驱动程序本质上为设备提供了一个软件接口。然后,您可以通过调用此设备驱动程序软件接口使事物出现在终端上。
  3. 在 *nix 系统中,设备驱动程序将它们控制的硬件设备公开为文件系统中的文件。您可以打开这些文件,并调用设备驱动程序提供的软件接口(通过 open、ioctl、close 等)。
  4. C 库有一个分层的 I/O 系统,它在下面打开这些文件并代表您调用设备驱动程序接口。你也可以自己做,但只要知道你使用的任何库函数也在做这个。
  5. 默认情况下,创建进程时,描述符 0 和 1 会在终端设备上打开。因此,当您写入这些描述符时,底层驱动程序会接收数据,并与硬件设备对话以在屏幕上呈现字符。
  6. 当您将一个进程的输出通过管道传输到另一个进程或将输出重定向到文件时,描述符会重新打开到其他设备(如管道或文件)上,并且您写入它们的数据最终会出现在相应的设备驱动程序中,最终是硬件设备。
于 2013-04-11T00:53:13.480 回答