基于WINAPI:如何计算aHandles[2]从启动到触发的时间差?
解决WaitForMultipleObjects场景下的两个需求:动态修改超时时间与记录句柄触发间隔
针对你的循环等待场景,我分两部分给出具体的实现方案,都是基于WINAPI的常规操作:
一、动态修改m_dwWaitTime的值
因为你的代码是在循环中反复调用WaitForMultipleObjects,要实现动态修改超时时间,核心是确保每次调用前获取最新的m_dwWaitTime值,同时要考虑多线程环境下的线程安全(如果有其他线程在修改这个值的话):
线程安全的读取方式:如果
m_dwWaitTime可能被其他线程修改,用Interlocked系列函数保证读取的原子性,避免出现半写半读的异常情况:// 每次等待前读取最新的超时时间 DWORD dwCurrentWaitTime = InterlockedRead((LONG*)&pRedir->m_dwWaitTime); DWORD dwRc = ::WaitForMultipleObjects(3, aHandles, FALSE, dwCurrentWaitTime);对于32位的
DWORD类型,InterlockedRead完全适配;如果是64位系统的更大数值类型,再对应调整函数即可。单线程场景简化版:如果只有当前线程会修改
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
相关产品推荐
相关产品推荐

