windows C/C++ 程序如何将自己置于后台?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/116701/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 11:16:59  来源:igfitidea点击:

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

windowslinuxmacosshellbackground

提问by Larry Gritz

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

从命令行启动的正在运行的 C 或 C++ 程序将自身置于后台的最佳方式是什么,相当于用户从 unix shell 启动并在命令末尾使用“&”?(但用户没有。)它是一个 GUI 应用程序,不需要任何外壳 I/O,因此没有理由在启动后绑定外壳。但我希望 shell 命令启动在没有“&”的情况下自动背景化(或在 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.

理想情况下,我想要一个适用于任何 Linux、OS X 和 Windows 的解决方案。(或者我可以使用#ifdef 选择单独的解决方案。)可以假设这应该在执行开始时完成,而不是在中间的某个地方。

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 anotherexecuted 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 itselfinto background.

另一种解决方案是立即启动另一个执行版本(使用“系统”或 CreateProcess),使用相同的命令行参数,但将子进程置于后台,然后让父进程退出。但是,与将自身置于后台的过程相比,这似乎很笨拙。

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.

在几个答案后编辑:是的,fork()(或 system(),或 Windows 上的 CreateProcess)是一种实现此目的的方法,我在我的原始问题中暗示了这一点。但是所有这些解决方案都会创建一个后台进程,然后终止原始进程。我想知道是否有办法将 EXISTING 进程置于后台。一个区别是,如果应用程序是从记录其进程 id 的脚本启动的(可能是为了以后杀死或其他目的),则新分叉或创建的进程将具有不同的 id,因此将不受任何启动脚本的控制,如果你明白我在说什么。

Edit #2:

编辑#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()."

fork() 对于 OS X 来说不是一个好的解决方案,其中“fork”的手册页说如果使用某些框架或库是不安全的。我试过了,我的应用程序在运行时大声抱怨:“进程已经分叉,你不能安全地使用这个 CoreFoundation 功能。你必须 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.

我对 daemon() 很感兴趣,但是当我在 OS X 上尝试它时,它给出了相同的错误消息,所以我认为它只是 fork() 的一个花哨的包装器并且具有相同的限制。

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.

原谅 OS X 中心主义,它恰好是我眼前的系统。但我确实在寻找所有三个平台的解决方案。

回答by Dan Lenski

My advice: don't do this, at least not under Linux/UNIX.

我的建议:不要这样做,至少不要在 Linux/UNIX 下这样做

GUI programs under Linux/UNIX traditionally do notauto-background themselves. While this may occasionally be annoying to newbies, it has a number of advantages:

Linux/UNIX 下的 GUI 程序传统上不会自动设置背景。虽然这有时可能会让新手感到恼火,但它有许多优点:

  • Makes it easy to capture standard error in case of core dumps / other problems that need debugging.

  • Makes it easy for a shell script to run the program and wait until it's completed.

  • Makes it easy for a shell script to run the program in the background and get its process id:

    gui-program &
    pid=$!
    # do something with $pid later, such as check if the program is still running
    

    If your program forks itself, this behavior will break.

  • 在核心转储/其他需要调试的问题的情况下,可以轻松捕获标准错误。

  • 使 shell 脚本可以轻松地运行程序并等待程序完成。

  • 使 shell 脚本可以轻松地在后台运行程序并获取其进程 ID:

    gui-program &
    pid=$!
    # do something with $pid later, such as check if the program is still running
    

    如果您的程序自己分叉,这种行为就会中断。

"Scriptability" is useful in so many unexpected circumstances, even with GUI programs, that I would hesitate to explicitly break these behaviors.

“可编写脚本”在许多意想不到的情况下很有用,即使是 GUI 程序,我也会犹豫是否明确打破这些行为。

Windows is another story. AFAIK, Windows programs automatically run in the background--even when invoked from a command shell--unless they explicitly request access to the command window.

Windows 是另一回事。AFAIK,Windows 程序会自动在后台运行——即使是从命令 shell 调用时——除非它们明确请求访问命令窗口。

回答by bstark

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

在 Linux 上,daemon()就是你要找的,如果我理解正确的话。

回答by Cody Brocious

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.

它通常在类 Unix 操作系统上完成的方式是在开始时 fork() 并从父级退出。这在 Windows 上不起作用,但比启动另一个存在分叉的进程要优雅得多。

回答by dsm

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

这适用于 POSIX 系统(您提到的所有系统都声称是 POSIX(但 Windows 停止在声明位))

回答by dsm

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

在 UNIX 上,您需要连续两次 fork 并让父节点死亡。

回答by Zan Lynx

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 notwait for process exit.

进程不能将自己置于后台,因为它不是负责后台与前台的进程。那就是 shell,它正在等待进程退出。如果你启动一个进程与符号“&”结尾,然后壳并没有等待进程退出。

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".

在 shell 中,您可以使用 Control-Z 将进程作为后台进程,然后键入“bg”。

回答by plinth

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

后台进程是一个 shell 函数,而不是一个 OS 函数。

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.

如果您希望应用程序在后台启动,典型的技巧是编写一个 shell 脚本来启动它,然后在后台启动它。

#! /bin/sh
/path/to/myGuiApplication &

回答by andy

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 definitionof being in the foreground.

您编辑了您的问题,但您可能仍然忽略了您的问题是某种语法错误这一点——如果该过程没有放在后台开始并且您希望 PID 保持不变,则可以' t 忽略启动进程的程序正在等待该 PID 的事实,这几乎是处于前台的定义

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.

我认为您需要考虑为什么要将某些内容放在后台并保持 PID 相同。我建议您可能不需要这两个约束。

回答by DGentry

To followup on your edited question:

要跟进您编辑的问题:

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

我想知道是否有办法将 EXISTING 进程置于后台。

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().

在类 Unix 的操作系统中,我所知道的确实没有办法做到这一点。shell 被阻塞,因为它正在执行 wait() 调用的变体之一,等待子进程退出。子进程没有办法保持运行,但不知何故导致 shell 的 wait() 以“请停止监视我”状态返回。您拥有子叉并退出原始分支的原因是外壳将从 wait() 返回。

回答by Zan Lynx

Here is some pseudocode for Linux/UNIX:

下面是一些适用于 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.

恭喜,您的程序继续作为一个独立的“守护进程”,没有控制 TTY,也没有任何标准输入或输出。

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.

现在,在 Windows 中,您只需使用 WinMain() 而不是 main() 将您的程序构建为 Win32 应用程序,并且它会在没有控制台的情况下自动运行。如果你想作为一项服务运行,你必须查看它,因为我从来没有写过一个,我真的不知道它们是如何工作的。