进程控制子系统(CategoryProcess)
SDL 提供了一套跨平台的进程控制接口,用于创建、管理和销毁操作系统级别的子进程,无需适配不同系统的原生进程 API(如 Windows 的 CreateProcess、Linux 的 fork/exec)。
核心使用流程
- 创建进程:通过
SDL_CreateProcess()创建基础子进程,或通过SDL_CreateProcessWithProperties()创建带高级属性(如 IO 重定向、进程链)的子进程; - 进程交互:使用
SDL_ReadProcess()、SDL_GetProcessInput()/SDL_GetProcessOutput()读写子进程的输入/输出流; - 进程管理:通过
SDL_WaitProcess()获取进程退出状态,或用SDL_KillProcess()强制终止进程; - 资源清理:无论进程是被杀死、自行退出还是仍在运行,都必须调用
SDL_DestroyProcess()释放进程相关资源。
函数
- SDL_CreateProcess:创建基础子进程,指定可执行文件路径和命令行参数,返回 SDL_Process 句柄(失败返回 NULL,可通过 SDL_GetError() 获取错误)
- SDL_CreateProcessWithProperties:创建带自定义属性的子进程(支持 IO 重定向、工作目录、环境变量等高级配置),返回 SDL_Process 句柄
- SDL_DestroyProcess:销毁进程句柄,释放所有关联资源(即使进程仍在运行,也需调用此函数清理;不会自动终止进程)
- SDL_GetProcessInput:获取子进程的标准输入(stdin)流句柄,用于向子进程写入数据
- SDL_GetProcessOutput:获取子进程的标准输出(stdout)或标准错误(stderr)流句柄,用于读取子进程输出
- SDL_GetProcessProperties:获取已创建进程的属性信息(如 IO 配置、进程 ID、工作目录等)
- SDL_KillProcess:强制终止指定的子进程(向进程发送终止信号,不同系统实现不同:Windows 用 TerminateProcess,Linux/macOS 用 kill)
- SDL_ReadProcess:简化版子进程输出读取函数,直接从子进程标准输出读取指定长度的数据
- SDL_WaitProcess:阻塞等待子进程退出,返回进程的退出码;若进程已退出,立即返回结果
数据类型
- SDL_Process:进程句柄类型(封装了平台相关的进程信息,如 Windows 的 HANDLE、Linux 的 pid_t),用于标识和管理子进程
结构体
- (无)
枚举
- SDL_ProcessIO:进程 IO 配置枚举,用于指定子进程的输入/输出流模式,常见值:
- SDL_PROCESS_IO_INHERIT:继承父进程的 IO 流(默认)
- SDL_PROCESS_IO_PIPE:创建管道用于父子进程间 IO 通信
- SDL_PROCESS_IO_NULL:重定向到空设备(忽略输入/输出)
宏
- (无)
FreeBASIC 示例代码
' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库)
#Include "SDL.bi"
' 补充类型和函数声明(FreeBASIC 绑定可能缺失)
Type SDL_Process As Any Ptr
' SDL_ProcessIO 枚举定义
Enum SDL_ProcessIO
SDL_PROCESS_IO_INHERIT = 0 ' 继承父进程IO
SDL_PROCESS_IO_PIPE = 1 ' 创建管道通信
SDL_PROCESS_IO_NULL = 2 ' 重定向到空设备
End Enum
' 进程属性结构体(简化版,实际 SDL 定义更完整)
Type SDL_ProcessProperties
io_stdin As SDL_ProcessIO ' 标准输入配置
io_stdout As SDL_ProcessIO ' 标准输出配置
io_stderr As SDL_ProcessIO ' 标准错误配置
working_directory As ZString Ptr ' 工作目录
environment As ZString Ptr Ptr ' 环境变量
End Type
' 核心函数声明
Declare Function SDL_CreateProcess CDecl (ByVal path As ZString Ptr, ByVal args As ZString Ptr Ptr) As SDL_Process
Declare Function SDL_CreateProcessWithProperties CDecl (ByVal path As ZString Ptr, ByVal args As ZString Ptr Ptr, ByVal props As SDL_ProcessProperties Ptr) As SDL_Process
Declare Sub SDL_DestroyProcess CDecl (ByVal process As SDL_Process)
Declare Function SDL_GetProcessInput CDecl (ByVal process As SDL_Process) As SDL_IOStream Ptr
Declare Function SDL_GetProcessOutput CDecl (ByVal process As SDL_Process) As SDL_IOStream Ptr
Declare Function SDL_GetProcessProperties CDecl (ByVal process As SDL_Process, ByVal props As SDL_ProcessProperties Ptr) As Integer
Declare Function SDL_KillProcess CDecl (ByVal process As SDL_Process) As Integer
Declare Function SDL_ReadProcess CDecl (ByVal process As SDL_Process, ByVal buffer As Any Ptr, ByVal size As Integer) As Integer
Declare Function SDL_WaitProcess CDecl (ByVal process As SDL_Process, ByRef exit_code As Integer) As Integer
' 示例1:创建基础子进程并读取输出
Sub CreateBasicProcess()
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【示例1:创建基础子进程】")
' 定义命令行参数(根据平台适配)
Dim As ZString Ptr args(2)
#If Defined(SDL_PLATFORM_WINDOWS)
' Windows:执行 cmd /c echo 测试内容
Dim As ZString * 256 exePath = "cmd.exe"
args(0) = StrPtr("/c")
args(1) = StrPtr("echo Hello from child process (Windows)!")
args(2) = NULL
#Elif Defined(SDL_PLATFORM_LINUX) Or Defined(SDL_PLATFORM_MACOS)
' Linux/macOS:执行 echo 测试内容
Dim As ZString * 256 exePath = "/bin/echo"
args(0) = StrPtr("Hello from child process (Linux/macOS)!")
args(1) = NULL
#Else
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "不支持的平台")
Exit Sub
#EndIf
' 创建子进程
Dim As SDL_Process proc = SDL_CreateProcess(@exePath, @args(0))
If (proc = NULL) Then
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建进程失败:%s", SDL_GetError())
Exit Sub
End If
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "子进程创建成功")
' 读取子进程输出
Dim As UByte buffer(1023)
Dim As Integer readSize = SDL_ReadProcess(proc, @buffer(0), 1024)
If (readSize > 0) Then
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "子进程输出:%.*s", readSize, @buffer(0))
ElseIf (readSize = 0) Then
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "子进程无输出")
Else
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "读取子进程输出失败:%s", SDL_GetError())
End If
' 等待进程退出并获取退出码
Dim As Integer exitCode
If (SDL_WaitProcess(proc, exitCode) = 0) Then
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "子进程正常退出,退出码:%d", exitCode)
Else
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "等待进程退出失败:%s", SDL_GetError())
End If
' 销毁进程句柄(必须调用)
SDL_DestroyProcess(proc)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "进程句柄已销毁")
End Sub
' 示例2:创建带属性的进程(IO 重定向 + 自定义工作目录)
Sub CreateProcessWithProps()
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf & "【示例2:创建带属性的子进程】")
' 配置进程属性
Dim As SDL_ProcessProperties props
props.io_stdin = SDL_PROCESS_IO_NULL ' 标准输入重定向到空
props.io_stdout = SDL_PROCESS_IO_PIPE ' 标准输出创建管道
props.io_stderr = SDL_PROCESS_IO_PIPE ' 标准错误创建管道
props.working_directory = StrPtr(".") ' 工作目录为当前目录
props.environment = NULL ' 继承父进程环境变量
' 定义命令(执行目录列表命令)
Dim As ZString Ptr args(1)
Dim As ZString * 256 exePath
#If Defined(SDL_PLATFORM_WINDOWS)
exePath = "cmd.exe"
args(0) = StrPtr("/c dir")
args(1) = NULL
#Elif Defined(SDL_PLATFORM_LINUX) Or Defined(SDL_PLATFORM_MACOS)
exePath = "/bin/ls"
args(0) = StrPtr("-l")
args(1) = NULL
#Else
Exit Sub
#EndIf
' 创建带属性的进程
Dim As SDL_Process proc = SDL_CreateProcessWithProperties(@exePath, @args(0), @props)
If (proc = NULL) Then
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建带属性进程失败:%s", SDL_GetError())
Exit Sub
End If
' 等待进程完成
Dim As Integer exitCode
SDL_WaitProcess(proc, exitCode)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "带属性进程退出码:%d", exitCode)
' 销毁进程句柄
SDL_DestroyProcess(proc)
End Sub
' 示例3:强制终止长时间运行的进程
Sub KillLongRunningProcess()
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf & "【示例3:强制终止子进程】")
' 创建一个长时间运行的进程
Dim As ZString Ptr args(1)
Dim As ZString * 256 exePath
#If Defined(SDL_PLATFORM_WINDOWS)
' Windows:执行 timeout 10(等待10秒)
exePath = "timeout.exe"
args(0) = StrPtr("10")
args(1) = NULL
#Elif Defined(SDL_PLATFORM_LINUX) Or Defined(SDL_PLATFORM_MACOS)
' Linux/macOS:执行 sleep 10(等待10秒)
exePath = "/bin/sleep"
args(0) = StrPtr("10")
args(1) = NULL
#Else
Exit Sub
#EndIf
Dim As SDL_Process proc = SDL_CreateProcess(@exePath, @args(0))
If (proc = NULL) Then
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建进程失败:%s", SDL_GetError())
Exit Sub
End If
' 等待2秒后强制终止
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "等待2秒后终止进程...")
SDL_Delay(2000)
If (SDL_KillProcess(proc) = 0) Then
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "进程已强制终止")
Else
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "终止进程失败:%s", SDL_GetError())
End If
' 等待进程退出(确认终止)
Dim As Integer exitCode
SDL_WaitProcess(proc, exitCode)
' 销毁进程句柄
SDL_DestroyProcess(proc)
End Sub
' 主程序
Sub Main()
' 初始化 SDL
If (SDL_Init(0) < 0) Then
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError())
Exit Sub
End If
' 运行示例
CreateBasicProcess()
CreateProcessWithProps()
KillLongRunningProcess()
' 清理 SDL
SDL_Quit()
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf & "程序正常退出")
End Sub
' 运行主程序
Main()
核心知识点补充
-
跨平台进程创建差异: 平台 原生进程 API SDL 封装优势 Windows CreateProcess 无需处理 STARTUPINFO/PROCESS_INFORMATION 结构体 Linux fork + execve 无需手动处理子进程 fork 后的资源隔离 macOS fork + execvp 统一的错误处理和资源清理逻辑 -
SDL_ProcessIO 枚举使用场景:
SDL_PROCESS_IO_INHERIT:子进程直接使用父进程的控制台/终端(适合简单命令执行);SDL_PROCESS_IO_PIPE:父子进程通过管道通信(适合需要读取/写入子进程输出/输入的场景);SDL_PROCESS_IO_NULL:忽略子进程的 IO(适合后台运行、无需交互的进程)。
-
关键注意事项:
- 资源清理:无论进程状态如何,必须调用
SDL_DestroyProcess(),否则会导致资源泄漏; - 阻塞等待:
SDL_WaitProcess()是阻塞函数,若需非阻塞检测进程状态,可先调用SDL_KillProcess()或结合 SDL 事件循环; - 权限问题:创建进程时需确保可执行文件路径有执行权限,工作目录有访问权限;
- 参数传递:命令行参数数组必须以
NULL结尾(符合 C 语言参数传递规范)。
- 资源清理:无论进程状态如何,必须调用
-
错误处理建议:
- 所有进程创建/操作函数失败时返回 NULL/非0,需通过
SDL_GetError()获取具体错误信息; - 对长时间运行的进程,建议增加超时逻辑(如
SDL_Delay()+SDL_KillProcess()); - 读取子进程输出时,缓冲区大小需合理(避免溢出或截断)。
- 所有进程创建/操作函数失败时返回 NULL/非0,需通过
总结
-
核心优势:
- 跨平台统一的进程控制接口,无需适配不同系统的原生进程 API;
- 简化的 IO 重定向配置(通过 SDL_ProcessIO 枚举),无需手动创建管道/文件句柄;
- 完善的资源管理机制,
SDL_DestroyProcess()统一清理进程相关资源; - 兼容主流平台的进程终止、等待逻辑,降低跨平台开发成本。
-
使用建议:
- 简单进程创建优先使用
SDL_CreateProcess(),需要高级配置时使用SDL_CreateProcessWithProperties(); - 读取子进程输出时,优先使用
SDL_ReadProcess()(简化接口),复杂 IO 交互使用SDL_GetProcessOutput()获取流句柄; - 强制终止进程前,建议先尝试优雅退出(如向子进程发送信号),仅在必要时使用
SDL_KillProcess(); - 始终在进程使用完毕后调用
SDL_DestroyProcess(),即使进程已退出。
- 简单进程创建优先使用
-
关键点回顾:
SDL_Process是进程句柄核心类型,所有进程操作均基于此句柄;SDL_DestroyProcess()必须调用,是避免资源泄漏的关键;SDL_ProcessIO枚举控制进程 IO 模式,SDL_PROCESS_IO_PIPE是父子进程通信的核心配置;SDL_WaitProcess()阻塞等待进程退出,SDL_KillProcess()强制终止进程,需配合使用以保证进程状态可控。
评论一下?