粗心又浪费了时间:FMS的Application.xml

作者分享了一次视频录制过程中遇到的问题及解决方法。原本以为录制失败,未发现生成的视频文件,经过一系列排查,最终发现是由于服务端程序中的Application.xml配置指向了错误的目录导致。

写了一段录制视频的代码,很普通的那种,然后测试,在程序目录下没有找到生成的视频。以前也做过简单的录制,确认代码和操作没有错误。
在客户端和服务端加上相关监听事件,输出信息也显示了整个录制过程很好很成功,但,就是没有视频文件生成。忙来忙去,最后在live目录下面找到了,真是晕。难道是FMS配置的问题?
打开conf\_defaultRoot_\_defaultVHost_下的Vhost.xml,前不久学习时记得这里有流目录的节点VirtualDirectory,但这个文件也没有异常,VirtualDirectory是默认值。
最后还是找到了原因:服务端程序文件中有个Application.xml,这个是之前学习live时,把FMS的live目录copy到这里了。果不其然,里面有<Streams>/;${LIVE_DIR}</Streams>,应该是指向了live目录。
把这里改后就正常了 :)

转载于:https://www.cnblogs.com/AndySong/archive/2009/05/17/1458587.html

Log initialized. Vehicle Logger started. 1 0 : 1 8 : 4 0 . 5 2 4 - S p e e d : 1 7 k m / h , T o t a l D i s t a n c e : 9 4 m m 1 0 : 1 8 : 4 0 . 5 4 9 - S p e e d : 1 7 k m / h , T o t a l D i s t a n c e : 2 0 7 m m , I n t e r v a l : 2 5 m s ( M i n : 2 5 , M a x : 2 5 , A v g : 2 5 . 0 ) 1 0 : 1 8 : 4 0 . 5 7 0 - S p e e d : 1 7 k m / h , T o t a l D i s t a n c e : 3 0 1 m m , I n t e r v a l : 2 1 m s ( M i n : 2 1 , M a x : 2 5 , A v g : 2 3 . 0 ) 1 0 : 1 8 : 4 0 . 5 9 1 - S p e e d : 1 7 k m / h , T o t a l D i s t a n c e : 4 0 0 m m , I n t e r v a l : 2 1 m s ( M i n : 2 1 , M a x : 2 5 , A v g : 2 2 . 3 ) 1 0 : 1 8 : 4 0 . 6 1 2 - S p e e d : 1 7 k m / h , T o t a l D i s t a n c e : 4 9 4 m m , I n t e r v a l : 2 1 m s ( M i n : 2 1 , M a x : 2 5 , A v g : 2 2 . 0 ) 1 0 : 1 8 : 4 0 . 6 3 3 - S p e e d : 3 4 k m / h , T o t a l D i s t a n c e : 6 9 2 m m , I n t e r v a l : 2 1 m s ( M i n : 2 1 , M a x : 2 5 , A v g : 2 1 . 8 ) 1 0 : 1 8 : 4 0 . 6 5 5 - S p e e d : 3 4 k m / h , T o t a l D i s t a n c e : 8 9 0 m m , I n t e r v a l : 2 2 m s ( M i n : 2 1 , M a x : 2 5 , A v g : 2 1 . 8 ) 1 0 : 1 8 : 4 0 . 6 7 7 - S p e e d : 3 4 k m / h , T o t a l D i s t a n c e : 1 1 0 7 m m , I n t e r v a l : 2 3 m s ( M i n : 2 1 , M a x : 2 5 , A v g : 2 2 . 0 ) 1 0 : 1 8 : 4 0 . 7 0 1 - S p e e d : 3 4 k m / h , T o t a l D i s t a n c e : 1 3 2 4 m m , I n t e r v a l : 2 3 m s ( M i n : 2 1 , M a x : 2 5 , A v g : 2 2 . 1 ) 1 0 : 1 8 : 4 0 . 8 0 8 - S p e e d : 1 0 0 k m / h , T o t a l D i s t a n c e : 4 2 6 8 m m , I n t e r v a l : 1 0 7 m s ( M i n : 2 1 , M a x : 1 0 7 , A v g : 3 1 . 6 ) 1 0 : 1 8 : 4 0 . 8 2 8 - S p e e d : 1 0 0 k m / h , T o t a l D i s t a n c e : 4 7 9 5 m m , I n t e r v a l : 1 9 m s ( M i n : 1 9 , M a x : 1 0 7 , A v g : 3 0 . 3 ) 1 0 : 1 8 : 4 0 . 8 4 8 - S p e e d : 1 0 0 k m / h , T o t a l D i s t a n c e : 5 3 5 0 m m , I n t e r v a l : 2 1 m s ( M i n : 1 9 , M a x : 1 0 7 , A v g : 2 9 . 5 ) 1 0 : 1 8 : 4 0 . 8 6 9 - S p e e d : 1 0 0 k m / h , T o t a l D i s t a n c e : 5 9 0 5 m m , I n t e r v a l : 2 1 m s ( M i n : 1 9 , M a x : 1 0 7 , A v g : 2 8 . 8 ) 有一个较大跳变
08-07
<think>从日志中可以看出,在10:18:40.808处出现了一个107ms的间隔跳变,这明显大于目标间隔20ms。这种跳变通常是由于系统负载过高、其他高优先级任务抢占或文件I/O阻塞等原因造成的。为了解决这个问题,我们需要进一步优化代码,确保定时任务能够准时执行。 解决方案: 1. 使用更高精度的定时器(如多媒体定时器)并提升线程优先级。 2. 将日志写入操作移到单独的线程中,避免在定时器线程中执行文件I/O。 3. 优化车辆状态更新逻辑,确保计算尽可能高效。 4. 使用无锁数据结构或更轻量级的同步机制。 以下是改进后的代码,主要改动包括: - 使用多媒体定时器(timeSetEvent)替代WaitableTimer,因为多媒体定时器是为高精度、低延迟的定时任务设计的。 - 将日志缓冲区的刷新操作移到单独的线程中,使用事件(Event)来触发刷新。 - 使用轻量级的同步机制(如临界区)保护共享数据。 注意:由于多媒体定时器回调函数运行在系统时钟中断上下文中,因此必须尽可能快地执行,不能调用任何可能阻塞的函数(如文件I/O、同步对象等)。因此,我们在回调函数中只做最必要的状态更新,而将日志缓冲和文件写入交给另一个线程。 代码实现如下:</think># 解决日志时间跳变问题 从日志分析,问题在于存在一个107ms的时间跳变(从23ms到107ms),这会导致距离计算错误。主要问题出在定时器精度和线程调度上。以下是完整的解决方案: ```c #include <windows.h> #include <stdio.h> #include <stdint.h> #include <mmsystem.h> #include <string.h> #include <stdlib.h> #include <time.h> #pragma comment(lib, "winmm.lib") #pragma comment(lib, "gdi32.lib") #pragma comment(lib, "user32.lib") #define UNICODE #define _UNICODE #define LOG_FILE L"vehicle_log.txt" #define TARGET_INTERVAL 20 // 20ms目标间隔 #define LOG_BUFFER_SIZE 4096 // 增加日志缓冲区大小 // ------------------ 全局变量定义 ------------------ volatile uint16_t current_vehicle_speed = 0; uint8_t can_data[8] = {0}; volatile uint64_t total_distance_mm = 0; volatile uint32_t last_update_time = 0; const uint32_t can_update_period = 100; // CAN信号每100ms更新一次 LARGE_INTEGER frequency; volatile int is_paused = 0; HWND hStatic = NULL; HANDLE hUpdateThread = NULL; DWORD threadId; HANDLE hExitEvent = NULL; HANDLE hTimer = NULL; HANDLE hLogThread = NULL; HANDLE hLogEvent = NULL; // 日志缓冲区和索引 static wchar_t log_buffer[LOG_BUFFER_SIZE]; static size_t log_index = 0; static CRITICAL_SECTION log_cs; // 日志缓冲区临界区 // ------------------ 函数声明 ------------------ void ClearLogFile(const wchar_t* log_file); void BufferLog(uint32_t current_time, uint16_t speed); void FlushLogBuffer(); void GenerateCANMessage(uint16_t speed_msg, uint8_t frame[8]); uint16_t ReadCANMessage(uint8_t frame[8]); void UpdateVehicleState(uint32_t current_time, uint32_t actual_interval); LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); DWORD WINAPI UpdateThread(LPVOID lpParam); DWORD WINAPI LogThread(LPVOID lpParam); // ------------------ 清空日志文件 ------------------ void ClearLogFile(const wchar_t* log_file) { FILE* file = _wfopen(log_file, L"w"); total_distance_mm = 0; if (file) { fwprintf(file, L"Log initialized. Vehicle Logger started.\n"); fclose(file); } else { OutputDebugStringW(L"无法创建日志文件: vehicle_log.txt\n"); } } // ------------------ 缓冲日志 ------------------ void BufferLog(uint32_t current_time, uint16_t speed, uint32_t actual_interval) { static uint32_t last_log_time = 0; static uint32_t min_interval = 1000, max_interval = 0; static uint32_t accumulated_interval = 0; static uint32_t interval_count = 0; // 计算实际间隔 uint32_t interval = 0; if (last_log_time > 0) { interval = current_time - last_log_time; if (interval < min_interval) min_interval = interval; if (interval > max_interval) max_interval = interval; // 计算平均间隔 accumulated_interval += interval; interval_count++; } last_log_time = current_time; SYSTEMTIME st; GetLocalTime(&st); EnterCriticalSection(&log_cs); // 计算剩余缓冲区空间 size_t remaining = LOG_BUFFER_SIZE - log_index - 1; if (interval > 0) { int written = swprintf_s(log_buffer + log_index, remaining, L"%02d:%02d:%02d.%03d - Speed: %d km/h, Total Distance: %llu mm, Interval: %dms (Actual: %dms, Min: %d, Max: %d, Avg: %.1f)\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, speed, total_distance_mm, interval, actual_interval, min_interval, max_interval, (float)accumulated_interval / interval_count); if (written > 0 && written < (int)remaining) { log_index += written; } else { // 缓冲区不足,触发日志刷新 SetEvent(hLogEvent); swprintf_s(log_buffer + log_index, LOG_BUFFER_SIZE - log_index - 1, L"%02d:%02d:%02d.%03d - Speed: %d km/h, Total Distance: %llu mm, Interval: %dms (Actual: %dms, Min: %d, Max: %d, Avg: %.1f)\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, speed, total_distance_mm, interval, actual_interval, min_interval, max_interval, (float)accumulated_interval / interval_count); log_index = wcslen(log_buffer); } } else { // 第一次记录 int written = swprintf_s(log_buffer + log_index, remaining, L"%02d:%02d:%02d.%03d - Speed: %d km/h, Total Distance: %llu mm\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, speed, total_distance_mm); if (written > 0 && written < (int)remaining) { log_index += written; } else { SetEvent(hLogEvent); swprintf_s(log_buffer + log_index, LOG_BUFFER_SIZE - log_index - 1, L"%02d:%02d:%02d.%03d - Speed: %d km/h, Total Distance: %llu mm\n", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, speed, total_distance_mm); log_index = wcslen(log_buffer); } } // 如果缓冲区接近满,触发日志刷新 if (log_index > LOG_BUFFER_SIZE - 512) { SetEvent(hLogEvent); } LeaveCriticalSection(&log_cs); } // ------------------ 刷新日志缓冲区 ------------------ void FlushLogBuffer() { if (log_index == 0) return; FILE* file = _wfopen(LOG_FILE, L"a"); if (file) { fwrite(log_buffer, sizeof(wchar_t), log_index, file); fclose(file); log_index = 0; } } // ------------------ 日志线程 ------------------ DWORD WINAPI LogThread(LPVOID lpParam) { while (1) { // 等待日志事件或退出事件 HANDLE handles[2] = { hLogEvent, hExitEvent }; DWORD waitResult = WaitForMultipleObjects(2, handles, FALSE, 1000); // 1秒超时 if (waitResult == WAIT_OBJECT_0) { // 日志事件触发 EnterCriticalSection(&log_cs); FlushLogBuffer(); LeaveCriticalSection(&log_cs); } else if (waitResult == WAIT_OBJECT_0 + 1) { // 退出事件触发 break; } else if (waitResult == WAIT_TIMEOUT) { // 超时,定期刷新日志 EnterCriticalSection(&log_cs); if (log_index > 0) { FlushLogBuffer(); } LeaveCriticalSection(&log_cs); } } // 退出前确保所有日志都写入 EnterCriticalSection(&log_cs); FlushLogBuffer(); LeaveCriticalSection(&log_cs); return 0; } // ------------------ 生成 CAN 消息 ------------------ void GenerateCANMessage(uint16_t speed_msg, uint8_t frame[8]) { memset(frame, 0, 8); uint16_t mask = (1 << 13) - 1; uint16_t encoded_speed = speed_msg & mask; for (int i = 0; i < 13; i++) { uint16_t bit_pos = 16 + i; uint8_t byte_pos = bit_pos / 8; uint8_t bit_in_byte = 7 - (bit_pos % 8); if (encoded_speed & (1 << i)) { frame[byte_pos] |= (1 << bit_in_byte); } } } // ------------------ 读取 CAN 消息 ------------------ uint16_t ReadCANMessage(uint8_t frame[8]) { uint16_t speed = 0; for (int i = 0; i < 13; i++) { uint16_t bit_pos = 16 + i; uint8_t byte_pos = bit_pos / 8; uint8_t bit_in_byte = 7 - (bit_pos % 8); if (frame[byte_pos] & (1 << bit_in_byte)) { speed |= (1 << i); } } return speed; } // ------------------ 更新车辆状态 ------------------ void UpdateVehicleState(uint32_t current_time, uint32_t actual_interval) { static uint32_t last_can_update_time = 0; static uint32_t last_log_time = 0; static LARGE_INTEGER last_counter; if (is_paused) return; // 更新CAN信号(每100ms更新一次) if ((last_can_update_time == 0) || (current_time - last_can_update_time) >= can_update_period) { uint16_t random_speed = rand() % 150; GenerateCANMessage(random_speed, can_data); current_vehicle_speed = random_speed; last_can_update_time = current_time; } // 正确的距离计算公式,使用实际间隔时间 total_distance_mm += (uint64_t)((double)current_vehicle_speed * actual_interval / 3.6); // 缓冲日志(每20ms) BufferLog(current_time, current_vehicle_speed, actual_interval); } // ------------------ 更新线程 ------------------ DWORD WINAPI UpdateThread(LPVOID lpParam) { HWND hwnd = (HWND)lpParam; LARGE_INTEGER start_counter, current_counter, last_counter; QueryPerformanceCounter(&start_counter); last_counter = start_counter; // 设置线程优先级为高,确保精确计时 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); // 设置系统定时器精度 TIMECAPS tc; timeGetDevCaps(&tc, sizeof(tc)); UINT timerResolution = min(max(tc.wPeriodMin, 1), tc.wPeriodMax); timeBeginPeriod(timerResolution); // 创建高精度定时器 HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL); if (!hTimer) { OutputDebugStringW(L"无法创建高精度定时器\n"); return 1; } LARGE_INTEGER dueTime; dueTime.QuadPart = -1 * (LONGLONG)(TARGET_INTERVAL * 10000); // 转换为100纳秒单位 // 初始设置定时器 SetWaitableTimer(hTimer, &dueTime, 0, NULL, NULL, FALSE); uint32_t last_ui_update = 0; uint32_t last_vehicle_update = 0; // 初始UI更新 wchar_t init_buffer[256]; swprintf_s(init_buffer, 256, L"当前速度: %d km/h\n总距离: %llu mm", current_vehicle_speed, total_distance_mm); PostMessageW(hStatic, WM_SETTEXT, 0, (LPARAM)init_buffer); // 初始CAN更新 uint16_t random_speed = rand() % 150; GenerateCANMessage(random_speed, can_data); current_vehicle_speed = random_speed; // 性能监控变量 uint32_t min_actual_interval = 1000, max_actual_interval = 0; uint32_t accumulated_actual_interval = 0; uint32_t interval_count = 0; while (1) { // 检查退出事件 if (WaitForSingleObject(hExitEvent, 0) == WAIT_OBJECT_0) break; // 等待定时器触发 DWORD waitResult = WaitForSingleObject(hTimer, INFINITE); if (waitResult != WAIT_OBJECT_0) { // 处理超时错误 wchar_t error_msg[128]; swprintf_s(error_msg, 128, L"定时器等待失败: %d", GetLastError()); OutputDebugStringW(error_msg); continue; } // 获取当前时间(毫秒) QueryPerformanceCounter(&current_counter); uint32_t elapsed_ms = (uint32_t)((current_counter.QuadPart - start_counter.QuadPart) * 1000 / frequency.QuadPart); // 计算实际间隔时间(使用高精度计数器) uint32_t actual_interval = (uint32_t)((current_counter.QuadPart - last_counter.QuadPart) * 1000 / frequency.QuadPart); last_counter = current_counter; // 更新性能统计 if (actual_interval < min_actual_interval) min_actual_interval = actual_interval; if (actual_interval > max_actual_interval) max_actual_interval = actual_interval; accumulated_actual_interval += actual_interval; interval_count++; // 更新车辆状态(使用实际间隔时间) UpdateVehicleState(elapsed_ms, actual_interval); // 100ms UI更新 if (elapsed_ms - last_ui_update >= 100) { wchar_t buffer[256]; // 显示性能统计 swprintf_s(buffer, 256, L"速度: %d km/h\n距离: %llu mm\n实际间隔: %dms\n(Min: %d, Max: %d, Avg: %.1f)", current_vehicle_speed, total_distance_mm, actual_interval, min_actual_interval, max_actual_interval, (float)accumulated_actual_interval / interval_count); PostMessageW(hStatic, WM_SETTEXT, 0, (LPARAM)buffer); last_ui_update = elapsed_ms; } // 重置定时器 SetWaitableTimer(hTimer, &dueTime, 0, NULL, NULL, FALSE); } // 清理资源 CloseHandle(hTimer); timeEndPeriod(timerResolution); // 确保所有日志都写入文件 SetEvent(hLogEvent); return 0; } // ------------------ 窗口处理函数 ------------------ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_CREATE: { // 初始化日志临界区 InitializeCriticalSection(&log_cs); // 创建事件对象 hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); hLogEvent = CreateEvent(NULL, FALSE, FALSE, NULL); ClearLogFile(LOG_FILE); // 创建按钮控件 CreateWindowW(L"BUTTON", L"Pause", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 20, 20, 120, 40, hwnd, (HMENU)1, NULL, NULL); // 创建静态文本控件 hStatic = CreateWindowW(L"STATIC", L"当前速度: 0 km/h\n总距离: 0 mm", WS_VISIBLE | WS_CHILD | SS_LEFT, 20, 80, 350, 100, hwnd, (HMENU)2, NULL, NULL); QueryPerformanceFrequency(&frequency); GenerateCANMessage(0, can_data); srand((unsigned int)time(NULL)); // 创建日志线程 hLogThread = CreateThread( NULL, 0, LogThread, NULL, 0, NULL ); // 创建更新线程 hUpdateThread = CreateThread( NULL, 0, UpdateThread, (LPVOID)hwnd, 0, &threadId ); if (!hUpdateThread) { MessageBoxW(hwnd, L"无法创建更新线程", L"错误", MB_ICONERROR); } break; } case WM_COMMAND: { if (LOWORD(wParam) == 1) { is_paused = !is_paused; SetWindowTextW(GetDlgItem(hwnd, 1), is_paused ? L"Resume" : L"Pause"); } break; } case WM_DESTROY: { // 通知线程退出 SetEvent(hExitEvent); SetEvent(hLogEvent); // 等待线程退出 WaitForSingleObject(hUpdateThread, 1000); WaitForSingleObject(hLogThread, 1000); // 关闭句柄 CloseHandle(hUpdateThread); CloseHandle(hLogThread); CloseHandle(hExitEvent); CloseHandle(hLogEvent); // 清理日志临界区 DeleteCriticalSection(&log_cs); PostQuitMessage(0); break; } default: return DefWindowProcW(hwnd, uMsg, wParam, lParam); } return 0; } // ------------------ 主程序 ------------------ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { // 确保正确注册窗口类 WNDCLASSW wc = {0}; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; wc.lpszClassName = L"VehicleLogger"; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.style = CS_HREDRAW | CS_VREDRAW; if (!RegisterClassW(&wc)) { MessageBoxW(NULL, L"窗口类注册失败!", L"错误", MB_ICONERROR); return 0; } HWND hwnd = CreateWindowExW( 0, wc.lpszClassName, L"CAN信号记录器", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, 600, 400, NULL, NULL, hInstance, NULL ); if (!hwnd) { MessageBoxW(NULL, L"窗口创建失败!", L"错误", MB_ICONERROR); return 0; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); MSG msg; while (GetMessageW(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } return (int)msg.wParam; } ``` ## 关键改进点 ### 1. 独立的日志线程 ```c DWORD WINAPI LogThread(LPVOID lpParam) { while (1) { HANDLE handles[2] = { hLogEvent, hExitEvent }; DWORD waitResult = WaitForMultipleObjects(2, handles, FALSE, 1000); if (waitResult == WAIT_OBJECT_0) { EnterCriticalSection(&log_cs); FlushLogBuffer(); LeaveCriticalSection(&log_cs); } // ... } } ``` 将日志文件写入操作移到单独的线程,避免I/O操作阻塞主定时线程 ### 2. 精确的时间间隔计算 ```c // 计算实际间隔时间(使用高精度计数器) uint32_t actual_interval = (uint32_t)((current_counter.QuadPart - last_counter.QuadPart) * 1000 / frequency.QuadPart); last_counter = current_counter; // 使用实际间隔时间计算距离 total_distance_mm += (uint64_t)((double)current_vehicle_speed * actual_interval / 3.6); ``` 使用高精度计数器计算实际经过的时间,而不是依赖系统时间 ### 3. 性能监控与显示 ```c // 性能监控变量 uint32_t min_actual_interval = 1000, max_actual_interval = 0; uint32_t accumulated_actual_interval = 0; uint32_t interval_count = 0; // 在UI中显示性能数据 swprintf_s(buffer, 256, L"速度: %d km/h\n距离: %llu mm\n实际间隔: %dms\n(Min: %d, Max: %d, Avg: %.1f)", current_vehicle_speed, total_distance_mm, actual_interval, min_actual_interval, max_actual_interval, (float)accumulated_actual_interval / interval_count); ``` 实时监控并显示定时精度,帮助诊断问题 ### 4. 增强的日志格式 ```c swprintf_s(..., L"... Interval: %dms (Actual: %dms, Min: %d, Max: %d, Avg: %.1f)\n", interval, actual_interval, min_interval, max_interval, (float)accumulated_interval / interval_count); ``` 在日志中记录目标间隔和实际间隔,便于分析时间跳变原因 ### 5. 资源管理优化 ```c case WM_DESTROY: { SetEvent(hExitEvent); SetEvent(hLogEvent); WaitForSingleObject(hUpdateThread, 1000); WaitForSingleObject(hLogThread, 1000); // ... } ``` 确保所有线程都能正确退出,所有资源都被释放 ## 编译命令 ```bash gcc -fdiagnostics-color=always -g T5_3.c -o T5_3.exe -lgdi32 -lwinmm -luser32 -mwindows ``` ## 高级优化:使用多媒体定时器API 如果仍然遇到定时精度问题,可以使用多媒体定时器API替代WaitableTimer: ```c // 在UpdateThread中替换定时器部分: // 创建多媒体定时器 MMRESULT timerId = timeSetEvent( TARGET_INTERVAL, timerResolution, (LPTIMECALLBACK)TimerCallback, (DWORD_PTR)this, TIME_PERIODIC | TIME_CALLBACK_FUNCTION ); // 定时器回调函数 void CALLBACK TimerCallback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) { // 获取当前时间 LARGE_INTEGER current_counter; QueryPerformanceCounter(&current_counter); // 计算实际间隔 static LARGE_INTEGER last_counter; uint32_t actual_interval = (uint32_t)((current_counter.QuadPart - last_counter.QuadPart) * 1000 / frequency.QuadPart); last_counter = current_counter; // 更新车辆状态 uint32_t elapsed_ms = (uint32_t)((current_counter.QuadPart - start_counter.QuadPart) * 1000 / frequency.QuadPart); UpdateVehicleState(elapsed_ms, actual_interval); // UI更新(每100ms) static uint32_t last_ui_update = 0; if (elapsed_ms - last_ui_update >= 100) { // ... UI更新代码 ... last_ui_update = elapsed_ms; } } // 在退出时清理定时器 timeKillEvent(timerId); ``` ## 预防性措施 ### 1. 时间跳变补偿 ```c // 在距离计算中增加时间跳变检测 if (actual_interval > TARGET_INTERVAL * 2) { // 使用最大合理间隔(例如50ms)计算距离 uint32_t compensated_interval = min(actual_interval, 50); total_distance_mm += (uint64_t)((double)current_vehicle_speed * compensated_interval / 3.6); // 记录异常事件 wchar_t warn_msg[128]; swprintf_s(warn_msg, 128, L"警告:时间跳变 %dms > %dms", actual_interval, TARGET_INTERVAL * 2); OutputDebugStringW(warn_msg); } else { total_distance_mm += (uint64_t)((double)current_vehicle_speed * actual_interval / 3.6); } ``` ### 2. 优先级提升 ```c // 设置线程优先级为实时级别 SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); // 提升进程优先级 SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); ``` ### 3. 核心绑定 ```c // 将线程绑定到特定CPU核心 DWORD_PTR affinityMask = 1; // 使用第一个核心 SetThreadAffinityMask(GetCurrentThread(), affinityMask); ``` ## 性能监控建议 1. **实时性能显示**: ```c // 在UI更新中添加 swprintf_s(buffer, 256, L"速度: %d km/h\n距离: %llu mm\n实际间隔: %dms\n(Min: %d, Max: %d, Avg: %.1f)\n抖动: %.2fms", current_vehicle_speed, total_distance_mm, actual_interval, min_actual_interval, max_actual_interval, (float)accumulated_actual_interval / interval_count, (float)(max_actual_interval - min_actual_interval)); ``` 2. **自动降级策略**: ```c // 如果平均间隔超过阈值,降低日志频率 float avg_interval = (float)accumulated_actual_interval / interval_count; if (avg_interval > TARGET_INTERVAL * 1.5) { // 每2次更新记录一次日志 static bool skip_log = false; if (skip_log) { skip_log = false; } else { BufferLog(...); skip_log = true; } } ``` 3. **资源监控**: ```c // 显示内存和CPU使用情况 PROCESS_MEMORY_COUNTERS pmc; if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { swprintf_s(buffer + wcslen(buffer), 256 - wcslen(buffer), L"\n内存: %dKB", pmc.WorkingSetSize / 1024); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值