函数

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_PATHG_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。这将成为子进程的环境。如果 envpNULL,则子进程将继承其父进程的环境。

flags 应为任何您希望影响函数行为的标志的按位 ORG_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_PATHG_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_fdstderr_fd 都传递一个 FD,并将它包括在 source_fds 中)。

source_fdstarget_fds 允许将此进程中的任意数量的 FD 重新映射到已生成进程中不同的 FD。如果 n_fds 大于 0,那么 source_fdstarget_fds 都必须是非 NULL 且长度相同。source_fds 中的每个 FD 都重新映射到 target_fds 中同一索引号的 FD 号。源 FD 和目标 FD 可能相等,以便简单地将 FD 传播到已生成进程。在标准 FD 之后处理 FD 重新映射,因此任何等于 stdin_fdstdout_fdstderr_fd 的目标 FD 都将在已生成进程中覆盖它们。

自 2.72 版起,Windows 支持 source_fds

G_SPAWN_FILE_AND_ARGV_ZERO 表示 argv 的第一个元素是要执行的文件,而剩余元素是要传递给此文件的实际参数向量。通常,g_spawn_async_with_pipes()argv[0] 用作要执行的文件,并将整个 argv 传递给子进程。

child_setupuser_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_outstdout_pipe_outstderr_pipe_out 位置填充有用于写入子进程的标准输入或从子进程的标准输出或标准错误读取的文件描述符。g_spawn_async_with_pipes() 的调用者必须在不再使用这些文件描述符时将其关闭。如果这些参数为 NULL,则不会创建相应的管道。

如果 stdin_pipe_outNULL,则除非设置了 G_SPAWN_CHILD_INHERITS_STDIN,否则将子进程的标准输入附加到 /dev/null

如果 stderr_pipe_outNULL,则除非设置了 G_SPAWN_STDERR_TO_DEV_NULL,否则子进程的标准错误定向到与父进程的标准错误相同的位置。

如果 stdout_pipe_outNULL,则除非设置了 G_SPAWN_STDOUT_TO_DEV_NULL,否则子进程的标准输出定向到与父进程的标准输出相同的位置。

error 可以为 NULL(忽略错误),也可以为非 NULL(报告错误)。如果设置了错误,则该函数返回 FALSE。即使错误发生在子进程中(例如,在 `argv[0] 中未找到可执行文件),也会报告错误。通常情况下,应将返回错误的message字段显示给用户。可能的错误为G_SPAWN_ERROR` 域中的错误。

如果发生错误,则 child_pidstdin_pipe_outstdout_pipe_outstderr_pipe_out 将不会填充有有效值。

如果 child_pid 不为 NULL 且未发生错误,则必须使用 g_spawn_close_pid() 关闭返回的进程引用。

在现代 UNIX 平台上,GLib 可以在内部使用由 posix_spawn() 驱动的有效流程启动代码。这具有避免在克隆父进程地址空间时产生 fork 时性能开销的优势,并避免与立即执行不同进程无关的相关内存超支检查。只要满足以下条件,就会使用此经过优化的代码路径

  1. 设置了 G_SPAWN_DO_NOT_REAP_CHILD
  2. 设置了 G_SPAWN_LEAVE_DESCRIPTORS_OPEN
  3. 未设置 G_SPAWN_SEARCH_PATH_FROM_ENVP
  4. working_directoryNULL
  5. child_setupNULL
  6. 程序为认可的二进制格式或有 shebang。否则,GLib 将必须通过 shell 执行该程序,而程序不是使用经过优化的代码路径执行的。

如果您正在编写 GTK 应用程序,而您正在生成的程序也是一个图形化应用程序,那么为确保存储的程序在正确的屏幕上打开其窗口,您可能需要使用 GdkAppLaunchContextGAppLaunchContext 或设置 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

类型: GSpawnChildSetupFunc

刚好位于 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_fdstarget_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;调用方将拥有该数据的权限,并且负责释放它。

返回值

类型: gboolean

在成功时返回 TRUE,在设置错误时返回 FALSE