C++ 中的 System() 调用及其在编程中的作用

2022-01-11 00:00:00 operating-system windows system dos c++

我经常听说使用 system("PAUSE") 是不好的做法,而是使用 std::cin.get() 代替.现在我对系统调用的理解是,它们将一个字符串输入系统命令行并与操作系统对话,因此 PAUSE 是一个 DOS 命令,可以暂停命令窗口中的输出.我认为这与具有不同关键字的 Mac 和 unix 类似,并且由于缺乏跨操作系统兼容性,不鼓励使用系统调用.(如果我有任何错误,请纠正我)

I've often heard that using system("PAUSE") is bad practice and to use std::cin.get() instead. Now my understanding of system calls is that they take a string which they enter into a system command line and talk with the OS, so PAUSE is a DOS command that pauses the output in the command window. I assume this works similarly with Mac and unix with different keywords, and using system calls is discouraged because of a lack of cross OS compatibility. (If I'm wrong with any of this, please correct me)

我的问题是:什么时候适合使用 system() 调用?它们应该如何应用?什么时候不应该应用它们?

my question is this: When is it appropriate to use system() calls? How should they be applied? When should they NOT be applied?

推荐答案

system("PAUSE") 肯定不太理想.使用对系统的调用会创建一个子进程,这在 Windows 上是相当昂贵的,并且无论如何在任何操作系统上都不是非常便宜.在嵌入式系统上,内存开销很大.

system("PAUSE") is certainly less than ideal. using a call to system creates a subprocess, which on windows is fairly expensive and in any case not terribly cheap on any operating system. On embedded systems the memory overhead is significant.

如果有任何方法可以在本地没有太多痛苦,那就去做吧.在等待用户按下单个按钮的情况下,cin.get() 将很难被击败.在这种情况下,您的应用程序进程只会在标准输入上阻塞,只设置几个对内核可见的标志,最重要的是,不会分配新内存,也不会创建新的调度实体,甚至不会创建中断处理程序.

If there is any way to do it without much pain natively then do it. In the case of waiting for the user to press a single button, cin.get() will be very hard to beat. In this case, your applications process will just block on stdin, setting only a few flags visible to the kernel, and most importantly, allocates no new memory and creates no new scheduling entities, not even an interrupt handler.

此外,它在具有所有 c++ 编译器的所有操作系统上都可以正常工作,因为它仅使用该语言非常标准部分的一个非常基本的特性,而不依赖于操作系统提供的任何东西.

Additionally, it will work the same on all operating systems with all c++ compilers, since it uses only a very basic feature of a very standard part of the language, rather than depend on anything the OS provides.

预测您担心它是否昂贵并不重要,因为整个 想法 是暂停.好吧,首先,如果它很贵,那么它会损害可能发生的其他任何事情的性能.有没有注意到(在 Windows 上)当一个应用程序启动时,其他已经打开的应用程序也变得不那么响应了?此外,您的用户可能不是一个活生生的人,而是另一个代表人类用户工作的程序(例如,一个 shell 脚本).该脚本已经知道下一步该做什么,并且可以在标准输入中预先填充一个字符以跳过等待.如果您在此处使用了子进程,则脚本将经历(人类可察觉的)延迟.如果脚本这样做数百(或数亿!)次,则可能需要几秒钟才能运行的脚本现在需要数天或数年.

predicting your concern that it doesn't matter if it's expensive because the whole idea is to pause. Well, first off, if its expensive, then it's going to hurt performance for anything else that might be going on. Ever notice (on windows) when one application is launching, other, already open apps become less responsive too? Additionally, your user might not be a live human, but rather another program working on behalf of a human user (Say, a shell script). The script already knows what to do next and can pre-fill stdin with a character to skip over the wait. If you have used a subprocess here, the script will experience a (noticeable to a human) delay. If the script is doing this hundreds (or hundreds of millions!) of times, a script that could take seconds to run now takes days or years.

何时使用system():当你需要做一些其他进程做的事情,而你不能轻易做到.system() 并不总是最好的选择,因为它做了两件有些限制的事情.首先,与子进程通信的唯一方法是通过命令行参数作为输入,返回值作为输出.第二个是父进程阻塞,直到子进程完成.这两个因素限制了系统可用的情况.

when to use system(): when you need to do something that another process does, that you can't do easily. system() isn't always the best candidate because it does two things that are somewhat limiting. First, the only way to communicate with the subprocess is by command line arguments as input and return value as output. The second is that the parent process blocks until the child process has completed. These two factors limit the cases in which system is useable.

在 unixy 系统上,大多数子进程使用 fork 发生,因为它允许同一个程序作为两个独立进程在同一个地方继续,一个作为另一个进程的子进程(除非你向操作系统索取).在 Linux 上,这特别优化,并且与创建 pthread 一样便宜.即使在速度不那么快的系统上,它仍然非常有用(正如 apache 进程池方法所证明的那样)(在 windows/unix 文档链接)

on unixy systems, most subprocesses happen with fork because it allows the same program to continue in the same place as two separate processes, one as a child of the other (which is hardly noticeable unless you ask for it from the OS). On Linux, this is especially well optimized, and about as cheap as creating a pthread. Even on systems where this is not as fast, it is still very useful (as demonstrated by the apache process-pool methodology) (unavailable on windows/link to unix docs)

其他情况(在 Windows 上也是如此!)通常由 popenexec 系列函数处理.popen 创建一个子进程和一个连接到子进程的标准输入或标准输出的全新管道.然后,父进程和子进程都可以同时运行并很容易地进行通信.(链接到 Windows 文档/链接到 unix 文档)

other cases (on windows too!) are often handled by popen or exec family of functions. popen creates a subprocess and a brand new pipe connecting to the subprocesses' stdin or stdout. Both parent and child processes can then run concurrently and communicate quite easily. (link to windows docs/link to unix docs)

exec* 系列函数(有几个,execl,execv 等)另一方面会导致当前程序被新程序替换.原始程序不可见地退出,新进程接管.当新进程返回时,它将返回到任何所谓的原始进程,就好像该进程在那个时候已经返回而不是消失一样.与 exit(system("command")) 相比,它的优点是不会创建新进程,从而节省时间和内存(尽管并不总是非常多)(链接到 Windows 文档/unix 文档的链接)

exec* family of functions (there are several, execl, execv and so on) on the other hand causes the current program to be replaced by the new program. The original program exits invisibly and the new process takes over. When then new process returns, it will return to whatever called the original process, as if that process had returned at that point instead of vanishing. The advantage of this over exit(system("command")) is that no new process is created, saving time and memory (though not always terribly much) (link to windows docs /link to unix docs)

system 可能被某些脚本工具用于调用某些配方操作中的多个步骤.例如,在某个时刻,程序可以使用 system 调用文本编辑器来编辑某个配置文件.它不需要太关心发生的事情,但它当然应该等到用户保存并关闭编辑器后再继续.然后它可以使用返回值来确定编辑会话是否成功,即编辑器实际上打开了请求的文件(并且编辑器本身完全存在!),但将从中读取会话的实际结果直接编辑文件,而不是与子进程通信.(链接到 Windows 文档/unix 文档链接)

system could plausibly be used by some scripted tool to invoke several steps in some recipe action. For example, at a certain point, a program could use system to invoke a text editor to edit some configuration file. It need not concern itself too much with what happens, but it should certainly wait until the user has saved and closed the editor before continuing. It can then use the return value to find out if the editing session was successful, in the sense that the editor actually opened the requested file (and that the editor itself existed at all!), but will read the actual results of the session from the edited file directly, rather than communicating with the subprocess. (link to windows docs/link to unix docs)

相关文章