views:

3556

answers:

20

What's the best way for a running C or C++ program that's been launched from the command line to put itself into the background, equivalent to if the user had launched from the unix shell with '&' at the end of the command? (But the user didn't.) It's a GUI app and doesn't need any shell I/O, so there's no reason to tie up the shell after launch. But I want a shell command launch to be auto-backgrounded without the '&' (or on Windows).

Ideally, I want a solution that would work on any of Linux, OS X, and Windows. (Or separate solutions that I can select with #ifdef.) It's ok to assume that this should be done right at the beginning of execution, as opposed to somewhere in the middle.

One solution is to have the main program be a script that launches the real binary, carefully putting it into the background. But it seems unsatisfying to need these coupled shell/binary pairs.

Another solution is to immediately launch another executed version (with 'system' or CreateProcess), with the same command line arguments, but putting the child in the background and then having the parent exit. But this seems clunky compared to the process putting itself into background.

Edited after a few answers: Yes, a fork() (or system(), or CreateProcess on Windows) is one way to sort of do this, that I hinted at in my original question. But all of these solutions make a SECOND process that is backgrounded, and then terminate the original process. I was wondering if there was a way to put the EXISTING process into the background. One difference is that if the app was launched from a script that recorded its process id (perhaps for later killing or other purpose), the newly forked or created process will have a different id and so will not be controllable by any launching script, if you see what I'm getting at.

Edit #2:

fork() isn't a good solution for OS X, where the man page for 'fork' says that it's unsafe if certain frameworks or libraries are being used. I tried it, and my app complains loudly at runtime: "The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec()."

I was intrigued by daemon(), but when I tried it on OS X, it gave the same error message, so I assume that it's just a fancy wrapper for fork() and has the same restrictions.

Excuse the OS X centrism, it just happens to be the system in front of me at the moment. But I am indeed looking for a solution to all three platforms.

+7  A: 

The way it's typically done on Unix-like OSes is to fork() at the beginning and exit from the parent. This won't work on Windows, but is much more elegant than launching another process where forking exists.

Cody Brocious
A: 

The most common way of doing this under Linux is via forking. The same should work on Mac, as for Windows I'm not 100% sure but I believe they have something similar.

Basically what happens is the process splits itself into two processes, and then the original one exits (returning control to the shell or whatever), and the second process continues to run in the background.

davr
+1  A: 

As others mentioned, fork() is how to do it on *nix. You can get fork() on Windows by using MingW or Cygwin libraries. But those will require you to switch to using GCC as your compiler.

In pure Windows world, you'd use CreateProcess (or one of its derivatives CreateProcessAsUser, CreateProcessWithLogonW).

Justin Rudd
+3  A: 

On UNIX, you need to fork twice in a row and let the parent die.

This is a legitimate way for "going background", although not the customary one (i.e. no need for double forking if doing setsid etc); so whoever voted it down, I believe they shouldn't. It's not "canonical", but it's helpful.
ΤΖΩΤΖΙΟΥ
There is a good reason for the double fork(), but you do have to do at least a setsid() in between. It ensures that the daemonized process is not a process group leader as well as having no controlling terminal.
Jonathan Leffler
A: 

I'm not sure about Windows, but on UNIX-like systems, you can fork() then setsid() the forked process to move it into a new process group that is not connected to a terminal.

R. Bemrose
+3  A: 

Three things need doing,

fork
setsid
redirect STDIN, STDOUT and STDERR to /dev/null

This applies to POSIX systems (all the ones you mention claim to be POSIX (but Windows stops at the claiming bit))

dsm
I'd expect it works for POSIX apps on Windows as well. But you have to realize that nobody writes POSIX apps on Windows (i.e. not an OS problem)
MSalters
A: 

If you need a script to have the PID of the program, you can still get it after a fork.

When you fork, save the PID of the child in the parent process. When you exit the parent process, either output the PID to STD{OUT,ERR} or simply have a return pid; statement at the end of main(). A calling script can then get the pid of the program, although it requires a certain knowledge of how the program works.

Branan
A: 

The simplest form of backgrounding is: if (fork() != 0) exit(0);

In unix, if you want to background an disassociate from the tty completely, you would do:

  1. Close all descriptors which may access a tty (usually 0 1 2).
  2. if (fork() != 0) exit(0);
  3. setpgroup(0,getpid()); /* Might be necessary to prevent a SIGHUP on shell exit. */
  4. signal(SIGHUP,SIG_IGN); /* just in case, same as using nohup to launch program. */
  5. fd=open("/dev/tty",O_RDWR);
  6. ioctl(fd,TIOCNOTTY,0); /* Disassociates from the terminal */
  7. close(fd);
  8. if (fork() != 0) exit(0); /* just for good measure */

That should fully daemonize your program.

Steve Baker
Please add a:9. chdir("/")Thanks :)
ΤΖΩΤΖΙΟΥ
+2  A: 

To followup on your edited question:

I was wondering if there was a way to put the EXISTING process into the background.

In a Unix-like OS, there really is not a way to do this that I know of. The shell is blocked because it is executing one of the variants of a wait() call, waiting for the child process to exit. There is not a way for the child process to remain running but somehow cause the shell's wait() to return with a "please stop watching me" status. The reason you have the child fork and exit the original is so the shell will return from wait().

DGentry
You can put a listener for SIGHUP, but not interactively
dsm
Ctrl-Z and "bg" command? I'ver never bothered to figure out how it works, but it has always worked for me.
MSalters
+1  A: 

Here is some pseudocode for Linux/UNIX:

initialization_code()
if(failure) exit(1)
if( fork() > 0 ) exit(0)
setsid()
setup_signal_handlers()
for(fd=0; fd<NOFILE; fd++) close(fd)
open("/dev/null", O_RDONLY)
open("/dev/null", O_WRONLY)
open("/dev/null", o_WRONLY)
chdir("/")

And congratulations, your program continues as an independent "daemonized" process without a controlling TTY and without any standard input or output.

Now, in Windows you simply build your program as a Win32 application with WinMain() instead of main(), and it runs without a console automatically. If you want to run as a service, you'll have to look that up because I've never written one and I don't really know how they work.

Zan Lynx
Really bad code, sorry. You assume that a) you are allowed to close stdin/stdout/stderr, b) that 0=stdin, 1=stdout|stderr, 2=stdout|stderr and c) that open() will fill the file descriptors again from 0 on.
Thorsten79
No, this is very standard daemonize code. You ARE always allowed to close 0,1,2 in Unix'ish. The open function always returns the first available fd, so if 0,1,2 are closed, the next opens will be 0,1,2.If you insist, you can use dup2() to force the fds to be 0,1,2 but it isn't necessary.
Zan Lynx
@Thorsten79: you obviously haven't done any POSIX programming, sorry. You might want to find a way to access a shell on a POSIXish system and try a 'man 2 open'. Typically, the first paragraph of the DESCRIPTION section will be a mind-opening experience.
ΤΖΩΤΖΙΟΥ
POSIX does guarantee (a) and (b), but not (c). However, because of code like this almost all systems do in practice obey (c).
wnoise
@wnoise: “The file descriptor returned by a successful call will be the lowest-numbered file descriptor not currently open for the process.” conforming to POSIX.1-2001 . File descriptors 0, 1 and 2 have just been closed, no other thread running, ergo…
ΤΖΩΤΖΙΟΥ
+3  A: 

A process cannot put itself into the background, because it isn't the one in charge of background vs. foreground. That would be the shell, which is waiting for process exit. If you launch a process with an ampersand "&" at the end, then the shell does not wait for process exit.

But the only way the process can escape the shell is to fork off another child and then let its original self exit back to the waiting shell.

From the shell, you can background a process with Control-Z, then type "bg".

Zan Lynx
Right, I was aware of this. The point of the question was whether the program itself could do something that was the equivalent of the user hitting Ctrl-Z and then running 'bg'.
Larry Gritz
Answered in the first paragraph and the answer is "No"
Zan Lynx
A process can always send a SUSP signal to itself, but that's only half of what Larry asked ;)
ΤΖΩΤΖΙΟΥ
+3  A: 

Backgrounding a process is a shell function, not an OS function.

If you want an app to start in the background, the typical trick is to write a shell script to launch it that launches it in the background.

#! /bin/sh
/path/to/myGuiApplication &
plinth
Larry Gritz
A: 

Under Windows, the closing thing you're going to get to fork() is loading your program as a Windows service, I think.

Here is a link to an intro article on Windows services... CodeProject: Simple Windows Service Sample

unforgiven3
+6  A: 

On Linux, daemon() is what you're looking for, if I understand you correctly.

bstark
So very close! Looks great for Linux, but on OS X it appears to just wrap fork() and give the same awful runtime error message about how it's not safe to fork when using certain framework libraries.
Larry Gritz
A: 

So, as you say, just fork()ing will not do the trick. What you must do is fork() and then re-exec(), as this code sample does:

#include stdio.h>
#include <unistd.h>
#include <string.h>

#include <CoreFoundation/CoreFoundation.h>

int main(int argc, char **argv)
{
    int i, j;

    for (i=1; i<argc; i++)
        if (strcmp(argv[i], "--daemon") == 0)
        {
            for (j = i+1; j<argc; j++)
                argv[j-1] = argv[j];

            argv[argc - 1] = NULL;

            if (fork()) return 0;

            execv(argv[0], argv);

            return 0;
        }


    sleep(1);

    CFRunLoopRun();

    CFStringRef hello = CFSTR("Hello, world!");

    printf("str: %s\n", CFStringGetCStringPtr(hello, CFStringGetFastestEncoding(hello)));

    return 0;
}

The loop is to check for a --daemon argument, and if it is present, remove it before re-execing so an infinite loop is avoided.

I don't think this will work if the binary is put into the path because argv[0] is not necessarily a full path, so it will need to be modified.

Rodrigo Queiro
+9  A: 
Dan
Windows *console* programs do not run in the background. Windows *GUI* programs don't have a notion of being in the forground or background relative to a console. They're just windows in the Z-order.
MSalters
+2  A: 
andy
A: 
A: 

In Unix, what I have learned to do that is using fork(). If you want to put a running process into background, fork it twice.

A: 

I was trying the solution.

Only one fork is needed from the parent process.

The most important point is that, after fork, parent process must die by calling _exit(0); and NOT by calling exit(0);

When _exit(0); is used, command prompt immediately returns on the shell.

This is the trick.

Srinivas Nayak