How can a C/C++ program put itself into background

2020-02-05 02:29发布

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.

20条回答
疯言疯语
2楼-- · 2020-02-05 03:08

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

查看更多
贪生不怕死
3楼-- · 2020-02-05 03:09

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 &
查看更多
Deceive 欺骗
4楼-- · 2020-02-05 03:09

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.

查看更多
【Aperson】
5楼-- · 2020-02-05 03:10

I was trying the solution.

Only one fork is needed from the parent process.

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

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

This is the trick.

查看更多
走好不送
6楼-- · 2020-02-05 03:12

You edited your question, but you may still be missing the point that your question is a syntax error of sorts -- if the process wasn't put in the background to begin with and you want the PID to stay the same, you can't ignore the fact that the program which started the process is waiting on that PID and that is pretty much the definition of being in the foreground.

I think you need to think about why you want to both put something in the background and keep the PID the same. I suggest you probably don't need both of those constraints.

查看更多
虎瘦雄心在
7楼-- · 2020-02-05 03:15

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.

查看更多
登录 后发表回答