System() calls in C++ and their roles in programming

19,274

Solution 1

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.

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.

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.

EDIT: 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.

EDIT2: 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.

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)

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* 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 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)

Solution 2

System calls are sent to the shell or command line interpreter of the OS (dos, bash, etc) and its up to the shell to do what it wants with this command.

You would avoid using these kind of calls as it would reduce your programs portability to work with other operating systems. I would think only when you are absolutely sure that your code is targeting a specific OS that you should use such calls.

Solution 3

By the way, system() call should never be used with binaries with SUID or SGID bit set, quoting from the man page:

Do not use system() from a program with set-user-ID or set-group-ID privileges, because strange values for some environment variables might be used to subvert system integrity. Use the exec(3) family of functions instead, but not execlp(3) or execvp(3). system() will not, in fact, work properly from programs with set-user-ID or set-group-ID privileges on systems on which /bin/sh is bash version 2, since bash 2 drops privileges on startup.

Solution 4

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

When you can't do the thing you're trying to do with your own code or a library (or the cost of implementing it outweighs the cost of launching a new process to do so). system() is pretty costly in terms of system resources compared to cin.get(), and as such it should only be used when absolutely necessary. Remember that system() typically launches both an entire new shell and whatever program you asked it to run, so thats two new executables being launched.

Solution 5

system() is used to ask the operating system to run a program.

Why would your program want the operating system to run a program? Well there are cases. Sometimes an external program or operating system command can perform a task that is hard to do in your own program. For example, an external program may operate with elevated privileges or access propriety data formats.

The system() function, itself, is fairly portable but the command string you pass it is likely to be very platform-specific -- though the command string can be pulled from local configuration data to make it more platform-agnostic.

Other functions like fork(), exec*(), spawn*() and CreateProcess() will give you much more control over the way you run the external program, but are platform-specific and may not be available on your platform of choice.

system("PAUSE") is an old DOS trick and is generally considered to be fairly grotty style these days.

Share:
19,274
Gordon Gustafson
Author by

Gordon Gustafson

ML Platform Engineer at Motional. Experience in devops, backend development, and ML.

Updated on July 26, 2022

Comments

  • Gordon Gustafson
    Gordon Gustafson over 1 year

    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)

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

  • Thomas L Holaday
    Thomas L Holaday almost 15 years
    Is there any difference in the handling of environment variables between exec and system?
  • SingleNegationElimination
    SingleNegationElimination almost 15 years
    @Thomas L Holaday: certain variations of exec allow you to specify different environment variables, others use the current environment. system always uses the current environment.