SDL3_API分类参考_定时器(CategoryTimer)

2026-3-6 / 0 评论 / 8 阅读

定时器子系统(CategoryTimer)

SDL 提供时间管理相关功能,主要用于处理(通常是)短时长的时间操作。

请注意,这与「日历时间(calendar time)」管理不同——日历时间功能由 CategoryTime 模块提供。

本模块涵盖以下核心能力:

  • 测量已流逝的时间(SDL_GetTicks()SDL_GetPerformanceCounter());
  • 让线程休眠指定时长(SDL_Delay()SDL_DelayNS()SDL_DelayPrecise());
  • 在指定时长后触发回调函数(SDL_AddTimer() 等)。

此外,SDL 还提供了实用的宏,用于不同时间单位之间的转换(如 SDL_SECONDS_TO_NS() 等)。


函数

  • SDL_AddTimer:添加毫秒级定时器(指定触发间隔和回调函数,定时器线程中执行回调)
  • SDL_AddTimerNS:添加纳秒级高精度定时器(以纳秒为单位指定触发间隔)
  • SDL_Delay:让当前线程休眠指定毫秒数(基础休眠函数,精度受系统限制)
  • SDL_DelayNS:让当前线程休眠指定纳秒数(纳秒级休眠,精度高于 SDL_Delay)
  • SDL_DelayPrecise:高精度休眠(尽可能精准地休眠指定毫秒数,减少误差)
  • SDL_GetPerformanceCounter:获取高性能计数器的当前值(用于高精度时间测量)
  • SDL_GetPerformanceFrequency:获取高性能计数器的频率(每秒计数次数)
  • SDL_GetTicks:获取 SDL 初始化后的毫秒数(从 SDL_Init 调用开始计时,溢出后循环)
  • SDL_GetTicksNS:获取 SDL 初始化后的纳秒数(高精度版本的 SDL_GetTicks)
  • SDL_RemoveTimer:移除指定的定时器(停止定时器触发,释放相关资源)

数据类型

  • SDL_NSTimerCallback:纳秒级定时器回调函数类型(定时器触发时执行的函数原型)
  • SDL_TimerCallback:毫秒级定时器回调函数类型(返回值为下一次触发间隔,返回0则停止)
  • SDL_TimerID:定时器唯一标识符(标识一个创建的定时器,用于移除操作)

结构体

  • (无)

枚举

  • (无)

  • SDL_MS_PER_SECOND:每秒的毫秒数(值为 1000)
  • SDL_MS_TO_NS:毫秒转换为纳秒(ms × 1000000)
  • SDL_NS_PER_MS:每毫秒的纳秒数(值为 1000000)
  • SDL_NS_PER_SECOND:每秒的纳秒数(值为 1000000000)
  • SDL_NS_PER_US:每微秒的纳秒数(值为 1000)
  • SDL_NS_TO_MS:纳秒转换为毫秒(ns ÷ 1000000)
  • SDL_NS_TO_SECONDS:纳秒转换为秒(ns ÷ 1000000000)
  • SDL_NS_TO_US:纳秒转换为微秒(ns ÷ 1000)
  • SDL_SECONDS_TO_NS:秒转换为纳秒(s × 1000000000)
  • SDL_US_PER_SECOND:每秒的微秒数(值为 1000000)
  • SDL_US_TO_NS:微秒转换为纳秒(us × 1000)

FreeBASIC 示例代码

' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库)
#Include "SDL.bi"

' 补充时间转换宏的定义(FreeBASIC 绑定可能缺失)
#Define SDL_MS_PER_SECOND 1000
#Define SDL_NS_PER_SECOND 1000000000ULL
#Define SDL_NS_PER_MS 1000000ULL
#Define SDL_NS_PER_US 1000ULL
#Define SDL_US_PER_SECOND 1000000ULL

#Define SDL_MS_TO_NS(ms) ((ULLong)(ms) * SDL_NS_PER_MS)
#Define SDL_NS_TO_MS(ns) ((ULLong)(ns) / SDL_NS_PER_MS)
#Define SDL_NS_TO_SECONDS(ns) ((Double)(ns) / SDL_NS_PER_SECOND)
#Define SDL_NS_TO_US(ns) ((ULLong)(ns) / SDL_NS_PER_US)
#Define SDL_SECONDS_TO_NS(s) ((ULLong)(s) * SDL_NS_PER_SECOND)
#Define SDL_US_TO_NS(us) ((ULLong)(us) * SDL_NS_PER_US)

' 全局变量:定时器控制标志
Dim Shared As Boolean g_quitTimer = False
Dim Shared As SDL_TimerID g_timerId = 0 ' 定时器ID

' 毫秒级定时器回调函数
Function TimerCallback CDecl (ByVal interval As UInteger, ByVal param As Any Ptr) As UInteger
    Static As Integer counter = 0
    counter += 1

    Dim As ZString Ptr timerName = Cast(ZString Ptr, param)
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "%s - 定时器触发(第%d次),间隔:%dms", timerName, counter, interval)

    ' 返回下一次触发间隔(返回0则停止定时器)
    If (g_quitTimer Or counter >= 5) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "%s - 定时器停止", timerName)
        Return 0
    End If

    Return interval ' 保持原间隔继续触发
End Function

' 纳秒级定时器回调函数(FreeBASIC 函数原型适配)
Function NSTimerCallback CDecl (ByVal interval As ULLong, ByVal param As Any Ptr) As ULLong
    Static As Integer counter = 0
    counter += 1

    Dim As ZString Ptr timerName = Cast(ZString Ptr, param)
    Dim As Double intervalSec = SDL_NS_TO_SECONDS(interval)
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "%s - 纳秒定时器触发(第%d次),间隔:%.3fs", timerName, counter, intervalSec)

    ' 返回下一次触发间隔(返回0则停止)
    If (counter >= 3) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "%s - 纳秒定时器停止", timerName)
        Return 0
    End If

    Return interval ' 保持原间隔
End Function

' 测量函数执行耗时(使用高性能计数器)
Sub MeasureFunctionTime()
    ' 获取高性能计数器频率(每秒计数次数)
    Dim As ULLong freq = SDL_GetPerformanceFrequency()
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "高性能计数器频率:%llu Hz", freq)

    ' 记录开始时间
    Dim As ULLong start = SDL_GetPerformanceCounter()

    ' 模拟耗时操作(循环1000万次)
    Dim As Integer i
    For i = 1 To 10000000
        ' 空循环
    Next

    ' 记录结束时间
    Dim As ULLong end_ = SDL_GetPerformanceCounter()

    ' 计算耗时(秒)
    Dim As Double elapsedSec = (end_ - start) / (Double)freq
    Dim As ULLong elapsedNs = SDL_SECONDS_TO_NS(elapsedSec)
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "耗时操作完成:")
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "  - 计数器差值:%llu", end_ - start)
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "  - 耗时:%.6f 秒", elapsedSec)
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "  - 耗时:%llu 纳秒", elapsedNs)
End Sub

' 主程序
Sub Main()
    ' 初始化 SDL(必须初始化定时器子系统)
    If (SDL_Init(SDL_INIT_TIMER) < 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError())
        Exit Sub
    End If

    ' ========== 1. 基础时间获取 ==========
    Dim As UInteger ticks = SDL_GetTicks()
    Dim As ULLong ticksNs = SDL_GetTicksNS()
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "SDL 初始化后时间:")
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "  - 毫秒数:%u ms", ticks)
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "  - 纳秒数:%llu ns", ticksNs)

    ' ========== 2. 测量函数耗时 ==========
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "开始测量函数耗时...")
    MeasureFunctionTime()

    ' ========== 3. 线程休眠测试 ==========
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "主线程休眠 1.5 秒(基础 Delay)...")
    Dim As UInteger sleepMs = 1500
    Dim As ULLong sleepNs = SDL_MS_TO_NS(sleepMs)

    Dim As ULLong sleepStart = SDL_GetPerformanceCounter()
    SDL_Delay(sleepMs) ' 基础毫秒休眠
    Dim As ULLong sleepEnd = SDL_GetPerformanceCounter()

    Dim As Double actualSleepSec = (sleepEnd - sleepStart) / (Double)SDL_GetPerformanceFrequency()
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "实际休眠时间:%.3f 秒(目标:%.3f 秒)", actualSleepSec, sleepMs / 1000.0)

    ' 高精度休眠测试
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "主线程高精度休眠 500ms...")
    SDL_DelayPrecise(500)

    ' ========== 4. 毫秒级定时器 ==========
    Dim As String timerName = "毫秒定时器"
    g_timerId = SDL_AddTimer(1000, @TimerCallback, StrPtr(timerName)) ' 1秒触发一次
    If (g_timerId = 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_TIMER, "创建毫秒定时器失败:%s", SDL_GetError())
    Else
        SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "创建毫秒定时器成功(ID:%d)", g_timerId)
    End If

    ' ========== 5. 纳秒级定时器 ==========
    Dim As String nsTimerName = "纳秒定时器"
    Dim As ULLong nsInterval = SDL_SECONDS_TO_NS(2.5) ' 2.5秒
    Dim As SDL_TimerID nsTimerId = SDL_AddTimerNS(nsInterval, @NSTimerCallback, StrPtr(nsTimerName))
    If (nsTimerId = 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_TIMER, "创建纳秒定时器失败:%s", SDL_GetError())
    Else
        SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "创建纳秒定时器成功(ID:%d,间隔:%.3fs)", nsTimerId, SDL_NS_TO_SECONDS(nsInterval))
    End If

    ' 主线程等待定时器执行完成(7秒)
    SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "主线程等待 7 秒...")
    SDL_Delay(7000)

    ' 手动停止定时器(演示用,实际回调返回0会自动停止)
    If (g_timerId <> 0) Then
        SDL_RemoveTimer(g_timerId)
        SDL_LogInfo(SDL_LOG_CATEGORY_TIMER, "手动移除毫秒定时器(ID:%d)", g_timerId)
    End If

    ' 清理 SDL
    SDL_Quit()

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序正常退出")
End Sub

' 补充定时器函数声明(FreeBASIC 绑定可能缺失)
Declare Function SDL_AddTimer CDecl (ByVal interval As UInteger, ByVal callback As SDL_TimerCallback, ByVal param As Any Ptr) As SDL_TimerID
Declare Function SDL_AddTimerNS CDecl (ByVal interval As ULLong, ByVal callback As SDL_NSTimerCallback, ByVal param As Any Ptr) As SDL_TimerID
Declare Function SDL_RemoveTimer CDecl (ByVal id As SDL_TimerID) As Integer
Declare Function SDL_GetPerformanceCounter CDecl () As ULLong
Declare Function SDL_GetPerformanceFrequency CDecl () As ULLong
Declare Function SDL_GetTicksNS CDecl () As ULLong
Declare Sub SDL_DelayPrecise CDecl (ByVal ms As UInteger)
Declare Sub SDL_DelayNS CDecl (ByVal ns As ULLong)

' 运行主程序
Main()

核心知识点补充

  1. 时间测量精度分级

    • 基础精度(毫秒级)SDL_GetTicks() —— 适合普通计时,精度约 1-10ms,受系统时钟影响;
    • 高精度(纳秒级)SDL_GetPerformanceCounter() —— 基于 CPU 高性能计数器,精度可达纳秒级,适合测量短耗时操作。
  2. 定时器核心规则

    • 定时器回调函数运行在独立的定时器线程中,不可执行阻塞操作(如 SDL_Delay),也不可调用 SDL 图形/事件相关函数;
    • 毫秒定时器回调返回值为下一次触发间隔(ms),返回 0 则停止定时器;
    • 纳秒定时器回调返回值为下一次触发间隔(ns),返回 0 则停止;
    • 需通过 SDL_RemoveTimer() 手动移除未自动停止的定时器,避免资源泄漏。
  3. 休眠函数差异 函数 时间单位 精度 适用场景
    SDL_Delay 毫秒 较低(~1ms) 普通休眠,对精度无要求
    SDL_DelayNS 纳秒 中等 纳秒级休眠需求
    SDL_DelayPrecise 毫秒 较高 需精准控制休眠时长
  4. 时间单位转换注意事项

    • 所有转换宏使用无符号长整型(ULLong)避免溢出;
    • 纳秒转秒/毫秒时建议用浮点型计算,避免整数截断丢失精度;
    • 高性能计数器计算耗时公式:耗时(秒) = (结束值 - 开始值) / 计数器频率

总结

  1. 核心优势

    • 提供从毫秒到纳秒的多精度时间管理能力,满足不同场景需求;
    • 高性能计数器可实现纳秒级耗时测量,适合性能分析;
    • 跨平台统一接口,屏蔽不同系统的定时器/休眠实现差异;
    • 内置时间单位转换宏,简化单位换算逻辑。
  2. 使用建议

    • 初始化 SDL 时必须指定 SDL_INIT_TIMER 子系统,否则定时器函数会失败;
    • 普通计时用 SDL_GetTicks(),高精度计时用 SDL_GetPerformanceCounter()
    • 定时器回调函数需保持轻量,避免阻塞;
    • 休眠时长较短(<10ms)且要求精准时,优先使用 SDL_DelayPrecise()
  3. 关键接口

    • 时间测量:SDL_GetTicks()/SDL_GetPerformanceCounter()/SDL_GetPerformanceFrequency()
    • 线程休眠:SDL_Delay()/SDL_DelayPrecise()/SDL_DelayNS()
    • 定时器:SDL_AddTimer()/SDL_AddTimerNS()/SDL_RemoveTimer()
    • 单位转换:SDL_MS_TO_NS()/SDL_NS_TO_SECONDS()/SDL_SECONDS_TO_NS()

评论一下?

OωO
取消