Windows下高精准延时任务的最佳实践案例(可以精确到1ms)
最优代码:
#define _CRT_SECURE_NO_WARNINGS #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <iostream> #include <winsock2.h> #pragma comment(lib,"ws2_32") #include <mmsystem.h> #pragma comment(lib,"winmm") static uint64_t num = 0; static SOCKET m_udp_socket_fd = -1; static struct sockaddr_in m_dest_addr = { 0 }; #include <thread> #include <map> std::map<uint64_t, uint8_t> uMap = {}; static uint64_t uCurrTime = 0, uLastTime = 0; void InitUdpSock() { m_udp_socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (m_udp_socket_fd == -1) { perror("socket failed!\n"); return; } //设置目的IP地址 uint16_t port = 12345; const std::string& host = "2.168.1.50"; m_dest_addr.sin_family = AF_INET;//使用IPv4协议 m_dest_addr.sin_port = htons(port);//设置接收方端口号 m_dest_addr.sin_addr.s_addr = inet_addr(host.c_str()); //设置接收方IP } void ExitUdpSock() { closesocket(m_udp_socket_fd); } std::time_t GetTimestamp() { return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch()).count(); } void StartSendCpp11() { uCurrTime = GetTimestamp(); if (uLastTime != uCurrTime) { uLastTime = uCurrTime; char cData[128] = { 0 }; snprintf(cData, 127, "==========================%lld", num++); sendto(m_udp_socket_fd, cData, strlen(cData), 0, (struct sockaddr*)&m_dest_addr, sizeof(m_dest_addr)); } } int cpp11_testmain() { auto t = std::thread([]() { while (true) { StartSendCpp11(); std::this_thread::sleep_for(std::chrono::nanoseconds(100)); //当前线程挂起一毫秒 } }); while (true) { printf("go...\n"); std::this_thread::sleep_for(std::chrono::nanoseconds(100)); //当前线程挂起一毫秒 } t.join(); return 0; } int main(int argc, char** argv) { WSADATA wsadata = { 0 }; (void)WSAStartup(MAKEWORD(2, 2), &wsadata); InitUdpSock(); { //cpp11 thread sleep方法(精确:1ms) cpp11_testmain(); ExitUdpSock(); WSACleanup(); return 0; }
优化代码:
#define _CRT_SECURE_NO_WARNINGS #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <iostream> #include <winsock2.h> #pragma comment(lib,"ws2_32") #include <mmsystem.h> #pragma comment(lib,"winmm") //定义时钟分辨率,以ms为单位 #define TIMER_ACCURACY 1 MMRESULT g_mmTimerId = 0; UINT g_wAccuracy = 0; static uint64_t num = 0; static SOCKET m_udp_socket_fd = -1; static struct sockaddr_in m_dest_addr = { 0 }; void InitUdpSock() { m_udp_socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (m_udp_socket_fd == -1) { perror("socket failed!\n"); return; } //设置目的IP地址 uint16_t port = 12345; const std::string& host = "2.168.1.50"; m_dest_addr.sin_family = AF_INET;//使用IPv4协议 m_dest_addr.sin_port = htons(port);//设置接收方端口号 m_dest_addr.sin_addr.s_addr = inet_addr(host.c_str()); //设置接收方IP } void ExitUdpSock() { closesocket(m_udp_socket_fd); } void StartSend() { char cData[128] = { 0 }; snprintf(cData, 127, "%lld", num++); sendto(m_udp_socket_fd, cData, strlen(cData), 0, (struct sockaddr*)&m_dest_addr, sizeof(m_dest_addr)); } void CALLBACK TimerProc(UINT nID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD d2) { if (nID == g_mmTimerId) { StartSend(); } } // 释放定时器 void FreeHighTimer() { if (g_mmTimerId == 0) { return; } timeKillEvent(g_mmTimerId); timeEndPeriod(g_wAccuracy); } // 初始化高精度定时器 BOOL InitHighTimer() { TIMECAPS tc = { 0 }; //利用函数timeGetDeVCaps取出系统分辨率的取值范围,如果无错则继续; if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) == TIMERR_NOERROR) { //分辨率的值不能超出系统的取值范围 g_wAccuracy = min(max(tc.wPeriodMin, TIMER_ACCURACY), tc.wPeriodMax); //调用timeBeginPeriod函数设置定时器的分辨率 timeBeginPeriod(g_wAccuracy); // 设定1毫秒定时器 g_mmTimerId = timeSetEvent(1, 0, TimerProc, NULL, TIME_PERIODIC); if (g_mmTimerId == 0) { std::cout << "timeSetEvent failed: %d" << GetLastError() << std::endl; return FALSE; } return TRUE; } return FALSE; } int main(int argc, char** argv) { WSADATA wsadata = { 0 }; (void)WSAStartup(MAKEWORD(2, 2), &wsadata); InitUdpSock(); InitHighTimer(); (void)getchar(); FreeHighTimer(); ExitUdpSock(); WSACleanup(); return 0; }
带有高精度延迟计时函数的代码:
#define _CRT_SECURE_NO_WARNINGS #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <iostream> #include <winsock2.h> #pragma comment(lib,"ws2_32") #include <mmsystem.h> #pragma comment(lib,"winmm") // 休眠指定毫秒数 void MSleep(long lTime) { LARGE_INTEGER litmp; LONGLONG QPart1, QPart2; double dfMinus, dfFreq, dfTim, dfSpec; QueryPerformanceFrequency(&litmp); dfFreq = (double)litmp.QuadPart; QueryPerformanceCounter(&litmp); QPart1 = litmp.QuadPart; dfSpec = 0.000001 * lTime; do { QueryPerformanceCounter(&litmp); QPart2 = litmp.QuadPart; dfMinus = (double)(QPart2 - QPart1); dfTim = dfMinus / dfFreq; } while (dfTim < dfSpec); } //定义1ms和2s时钟间隔,以ms为单位 #define ONE_MILLI_SECOND 1 //定义时钟分辨率,以ms为单位 #define TIMER_ACCURACY 1 volatile DWORD g_nCounter = 0; volatile DWORD g_nCnt = 0; UINT64 g_nTicket = 0; LARGE_INTEGER g_xliPerfFreq = { 0 }; LARGE_INTEGER g_xliPerfStart = { 0 }; LARGE_INTEGER g_xliPerfNow = { 0 }; int g_nSecond = 0; MMRESULT g_mmTimerId = 0; UINT g_wAccuracy = 0; static uint64_t num = 0; static SOCKET m_udp_socket_fd = -1; static struct sockaddr_in m_dest_addr = { 0 }; void InitUdpSock() { m_udp_socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (m_udp_socket_fd == -1) { perror("socket failed!\n"); return; } //设置目的IP地址 uint16_t port = 12345; const std::string& host = "2.168.1.50"; m_dest_addr.sin_family = AF_INET;//使用IPv4协议 m_dest_addr.sin_port = htons(port);//设置接收方端口号 m_dest_addr.sin_addr.s_addr = inet_addr(host.c_str()); //设置接收方IP } void ExitUdpSock() { closesocket(m_udp_socket_fd); } // 自己去实现一个PING函数, 网上大把就不发了 int StartSend() { char cData[128] = { 0 }; snprintf(cData, 127, "%lld", num++); sendto(m_udp_socket_fd, cData, strlen(cData), 0, (struct sockaddr*)&m_dest_addr, sizeof(m_dest_addr)); return 1; } void CALLBACK TimerProc(UINT nID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD d2) { //double dtime = 0.0f; //char szBuffer[MAX_PATH] = { 0x00 }; //UINT64 nTemp = 0; if (nID == g_mmTimerId) { //g_nCounter++; g_nSecond += StartSend(); /*if (g_nCounter == 24) { QueryPerformanceCounter(&g_xliPerfNow); dtime = ((double)(g_xliPerfNow.QuadPart - g_xliPerfStart.QuadPart) * 1000000.0f) / (double)g_xliPerfFreq.QuadPart; if (dtime < 1000000.0f) { MSleep((1000000.0f - dtime)); } QueryPerformanceCounter(&g_xliPerfNow); dtime = ((double)(g_xliPerfNow.QuadPart - g_xliPerfStart.QuadPart) * 1000000.0f) / (double)g_xliPerfFreq.QuadPart; nTemp = GetTickCount64() - g_nTicket; snprintf(szBuffer, sizeof(szBuffer)/sizeof(*szBuffer) - 1, " [%04d] 执行时间 %lld 毫秒, \t%.9f 微秒, \t延时: %d ms", g_nCnt, nTemp, dtime, g_nSecond); std::cout << szBuffer << std::endl; g_nTicket = GetTickCount64(); memset(&g_xliPerfNow, 0x00, sizeof(LARGE_INTEGER)); memset(&g_xliPerfStart, 0x00, sizeof(LARGE_INTEGER)); memset(&g_xliPerfNow, 0x00, sizeof(LARGE_INTEGER)); QueryPerformanceFrequency(&g_xliPerfFreq); QueryPerformanceCounter(&g_xliPerfStart); g_nCnt++; g_nCounter = 0; g_nSecond = 0; }*/ } } // 释放定时器 void FreeHighTimer() { if (g_mmTimerId == 0) return; timeKillEvent(g_mmTimerId); timeEndPeriod(g_wAccuracy); } // 初始化高精度定时器 BOOL InitHighTimer() { TIMECAPS tc; QueryPerformanceFrequency(&g_xliPerfFreq); QueryPerformanceCounter(&g_xliPerfStart); g_nTicket = GetTickCount64(); //利用函数timeGetDeVCaps取出系统分辨率的取值范围,如果无错则继续; if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) == TIMERR_NOERROR) { //分辨率的值不能超出系统的取值范围 g_wAccuracy = min(max(tc.wPeriodMin, TIMER_ACCURACY), tc.wPeriodMax); //调用timeBeginPeriod函数设置定时器的分辨率 timeBeginPeriod(g_wAccuracy); // 设定1毫秒定时器 g_mmTimerId = timeSetEvent(1, 0, TimerProc, NULL, TIME_PERIODIC); if (g_mmTimerId == 0) { std::cout << "timeSetEvent failed: %d" << GetLastError() << std::endl; return FALSE; } return TRUE; } return FALSE; } int main(int argc, char** argv) { WSADATA wsadata = { 0 }; (void)WSAStartup(MAKEWORD(2, 2), &wsadata); InitUdpSock(); InitHighTimer(); (void)getchar(); FreeHighTimer(); ExitUdpSock(); WSACleanup(); return 0; }
收藏的用户(0)
X
正在加载信息~
2
最新回复 (0)