to system() or fork()/exec()?

24,363

Solution 1

system executes a command-interpreter, i.e. a shell, which (a) is slower than a direct fork/exec, (b) may behave differently on different systems and (c) is a potential security hazard if you pass it a string from an untrusted source. Also, system waits for the child process to exit, while you might want it to run concurrently with the parent process.

More in general, the low-level fork/exec gives you additional control: before or in between the two operations, you might want to chdir, open pipes, close file descriptors, set up shared memory, etc.

(By different systems, I don't mean Windows vs. Unix (as Windows doesn't even have fork): I'm talking Red Hat Linux vs. Ubuntu. The former uses Bash to execute what is passed to system, the latter a lightweight POSIX-compatible shell.)

Solution 2

fork() creates a new process. If you don't need to do that, just use system() (or popen()). You might want a second process to achieve parallelism, or for finer-grained control over the job, but often you just don't care for that if the job is meant to be synchronous.

On the other hand, I find that 95% of uses of system() are unnecessary or would somehow be better off done another way (e.g. using zlib instead of system("gzip")). So maybe the best answer is to use neither!

Solution 3

Going via system() additionally invokes a shell process, which might not be what you want.

Also the calling process is notified only when such shell dies not when the actual process run by the shell died.

Share:
24,363
Sparky
Author by

Sparky

Updated on September 02, 2020

Comments

  • Sparky
    Sparky over 3 years

    There appear to be two common ways of running an external executable from C in unix, the

    system()
    

    call and

    pid = fork()
    switch(pid)
    //switch statement based on return value of pid, 
    //one branch of which will include and exec() command
    

    Is there any reason to prefer a fork/exec over system in the case where they are functionally equivalent (parent process waits for child to finish, no complex information is returned from child)?.

  • John Zwinck
    John Zwinck about 11 years
    system("pause"); is a disease! It's like the most inefficient way to make your program wait for the user to type something.
  • Shark
    Shark about 11 years
    @JohnZwinck it was good enough for college :) was usually there to make the console 'stay there' when the program is about to exit.
  • John Zwinck
    John Zwinck about 11 years
    Next time, try something like cin >> dummy; (or scanf()). And don't think that work has higher standards than school!
  • Fred Foo
    Fred Foo about 11 years
    system("pause") is never needed on Unix systems, so this is irrelevant to the question.
  • Sparky
    Sparky about 11 years
    in this case it's a custom tool built by someone else, so I've either got to refactor their code into a library, call it via sys or exec, or copy over a chunk of the source into my own binaries. It's a tricky choice between speed of implementation maintainability.
  • John Zwinck
    John Zwinck about 11 years
    Just for completeness, there is one more choice: use a higher-level language like Python to invoke this third-party tool and also serve as the "main()" for your own code. That is, expose your own logic as a library or executable, and use a script of some sort to connect the pieces together, rather than shelling out from C. Food for thought.
  • Celeritas
    Celeritas over 9 years
    I asked my prof what the difference is and he said system() is an API to the OS and fork/exec are system level calls. Is this true? My understanding is that APIs to the OS are more secure in the sense they may contain additional checking, as opposed to system calls.
  • Fred Foo
    Fred Foo over 9 years
    @Celeritas In a sense (system calls are OS APIs as well), but your conclusion is false, as I've argued in the answer. system does not add checks; it adds unchecked functionality.
  • pelya
    pelya about 9 years
    Both system() and popen() actually create two new processes - one for the shell, and another for the command to be executed inside the shell.
  • John Zwinck
    John Zwinck almost 9 years
    @pelya: not necessarily: if the shell commands are built-in ones (of which e.g. Bash has many, like time), only a single new process is required.