You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于WINAPI:如何计算aHandles[2]从启动到触发的时间差?

解决WaitForMultipleObjects场景下的两个需求:动态修改超时时间与记录句柄触发间隔

针对你的循环等待场景,我分两部分给出具体的实现方案,都是基于WINAPI的常规操作:

一、动态修改m_dwWaitTime的值

因为你的代码是在循环中反复调用WaitForMultipleObjects,要实现动态修改超时时间,核心是确保每次调用前获取最新的m_dwWaitTime值,同时要考虑多线程环境下的线程安全(如果有其他线程在修改这个值的话):

  1. 线程安全的读取方式:如果m_dwWaitTime可能被其他线程修改,用Interlocked系列函数保证读取的原子性,避免出现半写半读的异常情况:

    // 每次等待前读取最新的超时时间
    DWORD dwCurrentWaitTime = InterlockedRead((LONG*)&pRedir->m_dwWaitTime);
    DWORD dwRc = ::WaitForMultipleObjects(3, aHandles, FALSE, dwCurrentWaitTime);
    

    对于32位的DWORD类型,InterlockedRead完全适配;如果是64位系统的更大数值类型,再对应调整函数即可。

  2. 单线程场景简化版:如果只有当前线程会修改m_dwWaitTime,直接读取变量就行,每次循环都会自动获取最新值:

    DWORD dwRc = ::WaitForMultipleObjects(3, aHandles, FALSE, pRedir->m_dwWaitTime);
    

二、记录aHandles[2]从启动等待到触发的时间间隔

要计算这个间隔,需要在开始等待的时刻记录时间戳,当检测到aHandles[2]触发时,再获取当前时间戳,两者的差值就是你要的时间间隔。这里推荐两种不同精度的实现方式:

方式1:毫秒级精度(简单易用,适合大多数场景)

用GetTickCount64()获取时间戳,无需额外初始化:

while (/* 你的循环持续条件 */) {
    // 记录等待开始的时间戳
    ULONGLONG ullWaitStart = GetTickCount64();
    
    DWORD dwCurrentWaitTime = InterlockedRead((LONG*)&pRedir->m_dwWaitTime);
    DWORD dwRc = ::WaitForMultipleObjects(3, aHandles, FALSE, dwCurrentWaitTime);
    
    if (dwRc == WAIT_OBJECT_0 + 2) {
        // 计算并输出时间间隔
        ULONGLONG ullNow = GetTickCount64();
        ULONGLONG ullElapsedMs = ullNow - ullWaitStart;
        printf("aHandles[2]触发,等待耗时:%llu 毫秒\n", ullElapsedMs);
        
        // 执行你的业务操作
        // ...
    } else if (dwRc == WAIT_TIMEOUT) {
        // 超时逻辑(如果需要)
        // ...
    } else {
        // 其他句柄触发或错误处理
        // ...
    }
}

方式2:微秒级精度(适合高精度计时需求)

用QueryPerformanceCounter()获取系统性能计数器,精度远高于毫秒级:

// 初始化计数器频率,只需要执行一次
LARGE_INTEGER liFreq;
QueryPerformanceFrequency(&liFreq);

while (/* 你的循环持续条件 */) {
    LARGE_INTEGER liStart;
    QueryPerformanceCounter(&liStart); // 记录等待开始时间
    
    DWORD dwCurrentWaitTime = InterlockedRead((LONG*)&pRedir->m_dwWaitTime);
    DWORD dwRc = ::WaitForMultipleObjects(3, aHandles, FALSE, dwCurrentWaitTime);
    
    if (dwRc == WAIT_OBJECT_0 + 2) {
        LARGE_INTEGER liEnd;
        QueryPerformanceCounter(&liEnd);
        
        // 转换为毫秒并保留两位小数
        double dElapsedMs = (liEnd.QuadPart - liStart.QuadPart) * 1000.0 / liFreq.QuadPart;
        printf("aHandles[2]触发,等待耗时:%.2f 毫秒\n", dElapsedMs);
        
        // 执行你的业务操作
        // ...
    }
    // 其他情况处理
    // ...
}

额外说明

如果“启动”指的是aHandles[2]这个句柄的创建时刻,那你需要在创建句柄的代码处就记录时间戳,后续触发时用当前时间减去创建时的时间戳即可。

内容的提问来源于stack exchange,提问作者Saylee Lad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:25:41