SDL3_API分类参考_进程控制(CategoryProcess)

2026-3-7 / 0 评论 / 1 阅读

进程控制子系统(CategoryProcess)

SDL 提供了一套跨平台的进程控制接口,用于创建、管理和销毁操作系统级别的子进程,无需适配不同系统的原生进程 API(如 Windows 的 CreateProcess、Linux 的 fork/exec)。

核心使用流程

  1. 创建进程:通过 SDL_CreateProcess() 创建基础子进程,或通过 SDL_CreateProcessWithProperties() 创建带高级属性(如 IO 重定向、进程链)的子进程;
  2. 进程交互:使用 SDL_ReadProcess()SDL_GetProcessInput()/SDL_GetProcessOutput() 读写子进程的输入/输出流;
  3. 进程管理:通过 SDL_WaitProcess() 获取进程退出状态,或用 SDL_KillProcess() 强制终止进程;
  4. 资源清理:无论进程是被杀死、自行退出还是仍在运行,都必须调用 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()

核心知识点补充

  1. 跨平台进程创建差异 平台 原生进程 API SDL 封装优势
    Windows CreateProcess 无需处理 STARTUPINFO/PROCESS_INFORMATION 结构体
    Linux fork + execve 无需手动处理子进程 fork 后的资源隔离
    macOS fork + execvp 统一的错误处理和资源清理逻辑
  2. SDL_ProcessIO 枚举使用场景

    • SDL_PROCESS_IO_INHERIT:子进程直接使用父进程的控制台/终端(适合简单命令执行);
    • SDL_PROCESS_IO_PIPE:父子进程通过管道通信(适合需要读取/写入子进程输出/输入的场景);
    • SDL_PROCESS_IO_NULL:忽略子进程的 IO(适合后台运行、无需交互的进程)。
  3. 关键注意事项

    • 资源清理:无论进程状态如何,必须调用 SDL_DestroyProcess(),否则会导致资源泄漏;
    • 阻塞等待SDL_WaitProcess() 是阻塞函数,若需非阻塞检测进程状态,可先调用 SDL_KillProcess() 或结合 SDL 事件循环;
    • 权限问题:创建进程时需确保可执行文件路径有执行权限,工作目录有访问权限;
    • 参数传递:命令行参数数组必须以 NULL 结尾(符合 C 语言参数传递规范)。
  4. 错误处理建议

    • 所有进程创建/操作函数失败时返回 NULL/非0,需通过 SDL_GetError() 获取具体错误信息;
    • 对长时间运行的进程,建议增加超时逻辑(如 SDL_Delay() + SDL_KillProcess());
    • 读取子进程输出时,缓冲区大小需合理(避免溢出或截断)。

总结

  1. 核心优势

    • 跨平台统一的进程控制接口,无需适配不同系统的原生进程 API;
    • 简化的 IO 重定向配置(通过 SDL_ProcessIO 枚举),无需手动创建管道/文件句柄;
    • 完善的资源管理机制,SDL_DestroyProcess() 统一清理进程相关资源;
    • 兼容主流平台的进程终止、等待逻辑,降低跨平台开发成本。
  2. 使用建议

    • 简单进程创建优先使用 SDL_CreateProcess(),需要高级配置时使用 SDL_CreateProcessWithProperties()
    • 读取子进程输出时,优先使用 SDL_ReadProcess()(简化接口),复杂 IO 交互使用 SDL_GetProcessOutput() 获取流句柄;
    • 强制终止进程前,建议先尝试优雅退出(如向子进程发送信号),仅在必要时使用 SDL_KillProcess()
    • 始终在进程使用完毕后调用 SDL_DestroyProcess(),即使进程已退出。
  3. 关键点回顾

    • SDL_Process 是进程句柄核心类型,所有进程操作均基于此句柄;
    • SDL_DestroyProcess() 必须调用,是避免资源泄漏的关键;
    • SDL_ProcessIO 枚举控制进程 IO 模式,SDL_PROCESS_IO_PIPE 是父子进程通信的核心配置;
    • SDL_WaitProcess() 阻塞等待进程退出,SDL_KillProcess() 强制终止进程,需配合使用以保证进程状态可控。

评论一下?

OωO
取消