tags:

views:

209

answers:

3

Hi - I'm trying to execute an external program from inside my Linux C++ program.

I'm calling the method system("gedit") to launch an instance of the Gedit editor. However my problem is while the Gedit window is open, my C++ program waits for it to exit.

How can I call an external program without waiting for it to exit?

+5  A: 

You will need to use fork and exec

int fork_rv = fork();
if (fork_rv == 0)
{
    // we're in the child
    execl("/path/to/gedit", "gedit", 0);

    // in case execl fails
    _exit(1);
}
else if (fork_rv == -1)
{
    // error could not fork
}

You will also need to reap your child so as not to leave a zombie process.

void reap_child(int sig)
{
    int status;
    waitpid(-1, &status, WNOHANG);
}

int main()
{
    signal(SIGCHLD, reap_child);
    ...
}

In regards to zombie processes, you have a second option. It uses a bit more resources (this flavor forks twice), but the benefit is you can keep your wait closer to your fork which is nicer in terms of maintenance.

int fork_rv = fork();
if (fork_rv == 0)
{
    fork_rv = fork();
    if (fork_rv == 0)
    {
        // we're in the child
        execl("/path/to/gedit", "gedit", 0);

         // if execl fails
        _exit(1);
    }
    else if (fork_rv == -1)
    {
        // fork fails
        _exit(2);
    }

    _exit(0);
}
else if (fork_rv != -1)
{
    // parent wait for the child (which will exit quickly)
    int status;
    waitpid(fork_rv, &status, 0);
}
else if (fork_rv == -1)
{
    // error could not fork
}

What this last flavor does is create a child, which in turns creates a grandchild and the grandchild is what exec's your gedit program. The child itself exits and the parent process can reap it right away. So an extra fork but you keep all the code in one place.

R Samuel Klatchko
can you give an example how to use fork and exec together to call gedit?
ace
You should use `_exit` instead of `exit` here: otherwise you might end up with artifacts such as the same buffers being flushed by two different processes.
ephemient
@ephemient - thanks, I've fixed my example.
R Samuel Klatchko
Yay. Now, more nitpicks: you could use `signal(SIGCHLD, SIG_IGN)`, but if you install a signal handler, you should really use `sigaction` because `signal` has varying historical behaviors on different UNIXes whereas `sigaction` is more standardized (and more general). And what happens if multiple children should be reaped but you only enter the `SIGCHLD` handler once?
ephemient
How do i pass an argument to gedit ?Also i'm getting a warning while calling execl()warning: missing sentinel in function call
ace
To pass arguments to gedit, add extra parameters to your exec call `execl("/path/to/gedit", "gedit", "arg1", "arg2", 0);` Make sure you have that last `0`, that's the missing sentinel.
R Samuel Klatchko
gotcha...thanks...
ace
+2  A: 

Oh, let me say it!

http://en.wikipedia.org/wiki/Fork-exec

Fork! :)

Hostile Fork
thanks for the link, i have a better understanding of fork reading that.
ace
+1  A: 

First, did you try to launch in background with system("gedit&")?

If that does not work, try spawning a new thread and running gedit from there.

I presume that you are not concerned with the result of the edit, or the contents of the edited file?

Mawg
Just tried that, works well. Thanks for providing a different approach.
ace