函数
GLibspawn_async_with_pipes_and_fds
自:2.68
声明 [src]
gboolean
g_spawn_async_with_pipes_and_fds (
const gchar* working_directory,
const gchar* const* argv,
const gchar* const* envp,
GSpawnFlags flags,
GSpawnChildSetupFunc child_setup,
gpointer user_data,
gint stdin_fd,
gint stdout_fd,
gint stderr_fd,
const gint* source_fds,
const gint* target_fds,
gsize n_fds,
GPid* child_pid_out,
gint* stdin_pipe_out,
gint* stdout_pipe_out,
gint* stderr_pipe_out,
GError** error
)
说明 [src]
以异步方式执行子程序(你的程序将不会在等待子程序退出时阻塞)
子程序由唯一必须提供的参数 argv
指定。argv
应当是一个以 NULL
结尾的字符串数组,要作为子程序的参数向量传递。argv
中的第一个字符串当然是要执行的程序的名称。默认情况下,程序的名称必须是完整路径。如果 flags
包含 G_SPAWN_SEARCH_PATH
标志,则将使用 PATH
环境变量来搜索可执行文件。如果 flags
包含 G_SPAWN_SEARCH_PATH_FROM_ENVP
标志,则将使用 envp
中的 PATH
变量来搜索可执行文件。如果 G_SPAWN_SEARCH_PATH
和 G_SPAWN_SEARCH_PATH_FROM_ENVP
标志都已设置,则 envp
中的 PATH
变量优先于环境变量。
如果程序名称不是完整路径,并且未使用 G_SPAWN_SEARCH_PATH
标志,则将从当前目录(或指定的 working_directory
)运行程序;在当前目录为全世界可写的情况下,这在某些情况下可能是意外的,甚至是危险的。
在 Windows 上,请注意,此函数和其它 g_spawn*()
函数的所有字符串或字符串向量参数都在 UTF-8(GLib 文件名编码)中。如果已在这些参数中传递的 Unicode 字符不是系统代码页的一部分,则只有在已使用宽字符 API 来检索其命令行的情况下,才可以正确地在已生成的程序中使用这些字符。对于使用 Microsoft 的工具构建的 C 程序,只需让程序拥有 wmain()
,而不是拥有 main()
,就已足够。wmain()
有一个宽字符参数向量作为参数。
至少目前,mingw 不支持 wmain()
,所以如果你使用 mingw 来开发已生成的程序,则它应当调用 g_win32_get_command_line()
来获取 UTF-8 中的参数。
在 Windows 上,底层的子进程创建 API CreateProcess()
不使用参数向量,而是使用命令行。C 运行库的 spawn*()
函数系列(g_spawn_async_with_pipes()
最终调用此系列函数)将参数向量元素粘贴在一起形成一条命令行,而 C 运行时启动代码会从命令行中对参数向量进行相应的重建,以传递给 main()
。当你拥有包含空格或双引号的参数向量元素时,就会出现复杂情况。spawn*()
函数不会执行任何引用或转义,但是启动代码会执行取消引用和取消转义,以便启用接收具有嵌入空格或双引号的参数。为了解决这种不对称性,g_spawn_async_with_pipes()
将对需要它的参数向量元素执行引用和转义操作,然后再调用 C 运行时 spawn()
函数。
Windows 上的返回的 child_pid
是对子进程的一个句柄,而不是其标识符。在 Windows 上,进程句柄和进程标识符是不同的概念。
envp
是以 NULL
结尾的字符串数组,其中,每个字符串的格式为 KEY=VALUE
。这将成为子进程的环境。如果 envp
为 NULL
,则子进程将继承其父进程的环境。
flags
应为任何您希望影响函数行为的标志的按位 OR。G_SPAWN_DO_NOT_REAP_CHILD
表示子进程不会自动释放;您必须使用子进程监视 (g_child_watch_add()) 来接收关于子进程消亡的通知,否则它将作为僵死进程存在,直到此进程退出。最后,您必须在 child_pid
上调用 g_spawn_close_pid()
,以便释放可能与子进程关联的资源。(在 Unix 中,使用子进程监视等同于手动调用 waitpid()
或处理 SIGCHLD
信号。在 Windows 中,调用 g_spawn_close_pid()
等同于在 child_pid
中返回的进程句柄上调用 CloseHandle()
)。请参见 g_child_watch_add()。
在子进程中标记为 FD_CLOEXEC
的打开 UNIX 文件描述符将自动关闭。G_SPAWN_LEAVE_DESCRIPTORS_OPEN
表示其他打开文件描述符将由子进程继承;否则,在子进程中调用 exec()
前,除了 stdin/stdout/stderr 之外所有描述符都将关闭。G_SPAWN_SEARCH_PATH
表示 argv
[0] 无需为绝对路径,它将在 PATH
环境变量中寻找该路径。G_SPAWN_SEARCH_PATH_FROM_ENVP
表示无需为绝对路径,它将在 envp
中的 PATH
变量中寻找该路径。如果同时使用 G_SPAWN_SEARCH_PATH
和 G_SPAWN_SEARCH_PATH_FROM_ENVP
,那么来自 envp
的值将优先于环境。
G_SPAWN_CHILD_INHERITS_STDIN
表示子进程将继承父进程的标准输入(默认情况下,将子进程的标准输入附加到 /dev/null
)。G_SPAWN_STDIN_FROM_DEV_NULL
显式施加默认行为。两种标志无法同时启用,并且在两种情况下,都将忽略 stdin_pipe_out
参数。
G_SPAWN_STDOUT_TO_DEV_NULL
表示子进程的标准输出将被丢弃(默认情况下,它会转到与父进程的标准输出相同的位置)。G_SPAWN_CHILD_INHERITS_STDOUT
显式施加默认行为。两种标志无法同时启用,并且在两种情况下,都将忽略 stdout_pipe_out
参数。
G_SPAWN_STDERR_TO_DEV_NULL
表示子进程的标准错误将被丢弃(默认情况下,它会转到与父进程的标准错误相同的位置)。G_SPAWN_CHILD_INHERITS_STDERR
显式施加默认行为。两种标志无法同时启用,并且在两种情况下,都将忽略 stderr_pipe_out
参数。
在多个参数中传递同一 FD 是有效的(例如,您可以为 stdout_fd
和 stderr_fd
都传递一个 FD,并将它包括在 source_fds
中)。
source_fds
和 target_fds
允许将此进程中的任意数量的 FD 重新映射到已生成进程中不同的 FD。如果 n_fds
大于 0,那么 source_fds
和 target_fds
都必须是非 NULL
且长度相同。source_fds
中的每个 FD 都重新映射到 target_fds
中同一索引号的 FD 号。源 FD 和目标 FD 可能相等,以便简单地将 FD 传播到已生成进程。在标准 FD 之后处理 FD 重新映射,因此任何等于 stdin_fd
、stdout_fd
或 stderr_fd
的目标 FD 都将在已生成进程中覆盖它们。
自 2.72 版起,Windows 支持 source_fds
。
G_SPAWN_FILE_AND_ARGV_ZERO
表示 argv
的第一个元素是要执行的文件,而剩余元素是要传递给此文件的实际参数向量。通常,g_spawn_async_with_pipes()
将 argv
[0] 用作要执行的文件,并将整个 argv
传递给子进程。
child_setup
和 user_data
是一个函数和用户数据。在 POSIX 平台上,在 GLib 执行其计划执行的所有设置(包括创建管道、关闭文件描述符等)且在调用 exec()
之前,在子进程中调用该函数。也就是说,在子进程中调用 exec()
之前调用 child_setup
。显然,此函数中的操作只会影响子进程,不会影响父进程。
Windows 上没有单独的 fork()
和 exec()
功能。使用单个 API 调用(CreateProcess()
)创建并运行子进程。Windows 上没有 child_setup
可以用到的公理,所以它会被忽略且不会调用。
如果为非 NULL
,则在 Unix 上,child_pid
将填充有子进程的进程 ID。可以使用进程 ID 向子进程发送信号,或在指定 G_SPAWN_DO_NOT_REAP_CHILD
标记时使用 g_child_watch_add()
(或 waitpid()
)。在 Windows 上,child_pid
仅当指定了 G_SPAWN_DO_NOT_REAP_CHILD
标志时才填充有对子进程的句柄。然后,可以使用 Win32 API 访问子进程,例如使用 WaitFor*()
函数等待进程终止,或使用 GetExitCodeProcess()
检查其退出代码。不再需要时,应使用 CloseHandle()
或 g_spawn_close_pid()
关闭句柄。
如果为非 NULL
,则会将 stdin_pipe_out
、stdout_pipe_out
、stderr_pipe_out
位置填充有用于写入子进程的标准输入或从子进程的标准输出或标准错误读取的文件描述符。g_spawn_async_with_pipes()
的调用者必须在不再使用这些文件描述符时将其关闭。如果这些参数为 NULL
,则不会创建相应的管道。
如果 stdin_pipe_out
为 NULL
,则除非设置了 G_SPAWN_CHILD_INHERITS_STDIN
,否则将子进程的标准输入附加到 /dev/null
。
如果 stderr_pipe_out
为 NULL,则除非设置了 G_SPAWN_STDERR_TO_DEV_NULL
,否则子进程的标准错误定向到与父进程的标准错误相同的位置。
如果 stdout_pipe_out
为 NULL,则除非设置了 G_SPAWN_STDOUT_TO_DEV_NULL
,否则子进程的标准输出定向到与父进程的标准输出相同的位置。
error
可以为 NULL
(忽略错误),也可以为非 NULL
(报告错误)。如果设置了错误,则该函数返回 FALSE
。即使错误发生在子进程中(例如,在 `argv
[0] 中未找到可执行文件),也会报告错误。通常情况下,应将返回错误的
message字段显示给用户。可能的错误为
G_SPAWN_ERROR` 域中的错误。
如果发生错误,则 child_pid
、stdin_pipe_out
、stdout_pipe_out
和 stderr_pipe_out
将不会填充有有效值。
如果 child_pid
不为 NULL
且未发生错误,则必须使用 g_spawn_close_pid() 关闭返回的进程引用。
在现代 UNIX 平台上,GLib 可以在内部使用由 posix_spawn()
驱动的有效流程启动代码。这具有避免在克隆父进程地址空间时产生 fork 时性能开销的优势,并避免与立即执行不同进程无关的相关内存超支检查。只要满足以下条件,就会使用此经过优化的代码路径
- 设置了
G_SPAWN_DO_NOT_REAP_CHILD
- 设置了
G_SPAWN_LEAVE_DESCRIPTORS_OPEN
- 未设置
G_SPAWN_SEARCH_PATH_FROM_ENVP
working_directory
为NULL
child_setup
为NULL
- 程序为认可的二进制格式或有 shebang。否则,GLib 将必须通过 shell 执行该程序,而程序不是使用经过优化的代码路径执行的。
如果您正在编写 GTK 应用程序,而您正在生成的程序也是一个图形化应用程序,那么为确保存储的程序在正确的屏幕上打开其窗口,您可能需要使用 GdkAppLaunchContext
、GAppLaunchContext
或设置 DISPLAY
环境变量。
2.68 起可使用
参数
working_directory
-
类型:
const gchar*
子代当前工作目录,或
NULL
以继承父代 GLib 文件名编码。参数可以为 NULL
。数据归属于该函数的调用方所有。 该值是一个平台原生字符串,在 Unix 上使用首选 OS 编码,在 Windows 上使用 UTF-8。 argv
-
类型: 一个
filename
数组子代参数向量,在 GLib 文件名编码中;它必须是非空的且以
NULL
结尾。该数组必须以 NULL
结尾。数据归属于该函数的调用方所有。 每个元素都是一个平台原生字符串,在 Unix 上使用首选 OS 编码,在 Windows 上使用 UTF-8。 envp
-
类型: 一个
filename
数组child's environment, or `NULL` to inherit parent's, in the GLib file name encoding.
参数可以为 NULL
。该数组必须以 NULL
结尾。数据归属于该函数的调用方所有。 每个元素都是一个平台原生字符串,在 Unix 上使用首选 OS 编码,在 Windows 上使用 UTF-8。 flags
-
类型:
GSpawnFlags
来自
GSpawnFlags
的标志。 child_setup
-
刚好位于
exec()
之前的子代中运行的函数。参数可以为 NULL
。 user_data
-
类型:
gpointer
child_setup
的用户数据。参数可以为 NULL
。数据归属于该函数的调用方所有。 stdin_fd
-
类型:
gint
用于子代 stdin 的文件描述符,或
-1
。 stdout_fd
-
类型:
gint
用于子代 stdout 的文件描述符,或
-1
。 stderr_fd
-
类型:
gint
用于子代 stderr 的文件描述符,或
-1
。 source_fds
-
类型: 一个
gint
数组可在子进程中获取的父进程 FD 数组。
参数可以为 NULL
。数组的长度在 n_fds
参数中指定。数据归属于该函数的调用方所有。 target_fds
-
类型: 一个
gint
数组要将
source_fds
重新映射到的子进程中 FD 的数组。参数可以为 NULL
。数组的长度在 n_fds
参数中指定。数据归属于该函数的调用方所有。 n_fds
-
类型:
gsize
source_fds
和target_fds
中的 FD 数目。 child_pid_out
-
类型:
GPid
子进程的 ID 返回位置,或
NULL
。此参数将由该函数设置。 参数可以为 NULL
。该函数调用方拥有返回数据的权限,并且负责释放它。 stdin_pipe_out
-
类型:
gint*
用于向子代的 stdin 中写入的文件描述符的返回位置,或
NULL
。此参数将由该函数设置。 参数可以为 NULL
。 stdout_pipe_out
-
类型:
gint*
用于读取子代的 stdout 文件描述符的返回位置,或
NULL
。此参数将由该函数设置。 参数可以为 NULL
。 stderr_pipe_out
-
类型:
gint*
用于读取子代的 stderr 文件描述符的返回位置,或
NULL
。此参数将由该函数设置。 参数可以为 NULL
。 error
-
类型:
GError **
用于 可修复错误 的返回位置。
参数可以为 NULL
。如果返回位置不为 NULL
,那么您必须将其初始化为一个NULL
GError*
。如果没有错误,则该参数将由该函数初始化并保留为 NULL
。如果出错,则该参数将设置为一个新分配的 GError
;调用方将拥有该数据的权限,并且负责释放它。