近期做了一个项目,需要服务器端按周期向客户端发送信息,需要使用定时器。
windows平台有好多个定时器函数,在这里记录一下我试过的几种。
另外linux下的定时器函数也记录在这儿。
1. CreateTimerQueueTimer
// 创建并启动定时器
BOOL WINAPI CreateTimerQueueTimer(
__out PHANDLE phNewTimer,
__in HANDLE TimerQueue,
__in WAITORTIMERCALLBACK Callback,
__in PVOID Parameter,
__in DWORD DueTime,
__in DWORD Period,
__in ULONG Flags
);
// 删除定时器
BOOL WINAPI DeleteTimerQueueTimer(
__in HANDLE TimerQueue,
__in HANDLE Timer,
__in HANDLE CompletionEvent
);
- 示例
点击(此处)折叠或打开
-
// 创建定时器
-
if (!CreateTimerQueueTimer(
-
&timerId, // timer handle
-
NULL, // the default timer queue
-
(WAITORTIMERCALLBACK)handler, // 回调函数
-
"test", // 传递给回调函数的数据
-
0, // timer启动延迟时间(毫秒)
-
1000, // 周期(毫秒)
-
0)) // flags
-
{
-
printf("CreateTimerQueueTimer error.(%d)", GetLastError());
-
}
-
-
// 回调函数
-
static void CALLBACK handler(PVOID lpParam, BOOLEAN TimerOrWaitFired)
-
{
-
const char* str = (const char*)lpParam;
-
printf("str=%s\n", str);
-
}
-
-
// 删除定时器
-
DeleteTimerQueueTimer(
-
NULL, // NULL, the default timer queue
-
timerId, // timer handle
- INVALID_HANDLE_VALUE); // 如果此参数设为NULL,有可能导致程序崩溃
2. timeSetEvent
// 创建并启动定时器
MMRESULT timeSetEvent(
UINT uDelay,
UINT uResolution,
LPTIMECALLBACK lpTimeProc,
DWORD_PTR dwUser,
UINT fuEvent);
// 删除定时器
MMRESULT timeKillEvent(UINT uTimerID);
- 示例
点击(此处)折叠或打开
-
// 创建定时器
-
timerId = timeSetEvent(1000, // 周期(毫秒)
-
100, // 精度(毫秒)
-
&handler, // 回调函数
-
(DWORD_PTR)"test", // 传递给回调函数的数据
-
// 定时器种别(一次性或周期性)
-
TIME_PERIODIC | TIME_KILL_SYNCHRONOUS | TIME_CALLBACK_FUNCTION);
-
if (timerId == NULL)
-
{
-
printf("timeSetEvent error.(%d)", GetLastError());
-
return;
-
}
-
-
// 回调函数
-
static void CALLBACK handler(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
-
{
-
const char* str = (const char*)dwUser;
-
printf("str=%s\n", str);
-
}
-
-
// 删除定时器
- timeKillEvent(timerId);
使用此种定时器函数需要依赖库文件Winmm.lib。
3. CreateWaitableTimer
// 创建定时器
HANDLE WINAPI CreateWaitableTimer(
__in LPSECURITY_ATTRIBUTES lpTimerAttributes,
__in BOOL bManualReset,
__in LPCTSTR lpTimerName
);
// 启动定时器
BOOL WINAPI SetWaitableTimer(
__in HANDLE hTimer,
__in const LARGE_INTEGER* pDueTime,
__in LONG lPeriod,
__in PTIMERAPCROUTINE pfnCompletionRoutine,
__in LPVOID lpArgToCompletionRoutine,
__in BOOL fResume
);
// 取消定时器,调用SetWaitableTimer可重新激活定时器
BOOL WINAPI CancelWaitableTimer(
__in HANDLE hTimer
);
- 示例
点击(此处)折叠或打开
-
// 创建定时器
-
hTimer = CreateWaitableTimer(
-
NULL, // Default security attributes
-
FALSE, // Create auto-reset timer
-
NULL); // Name of waitable timer
-
if (hTimer == NULL)
-
{
-
printf("CreateWaitableTimer error.(%d)", GetLastError());
-
return;
-
}
-
-
liDueTime.LowPart = 0;
-
liDueTime.HighPart = 0;
-
// 启动定时器
-
bSuccess = SetWaitableTimer(
-
hTimer, // Handle to the timer object
-
&liDueTime, // When timer will become signaled
-
1000, // Periodic timer interval
-
handler, // Completion routine
-
"test", // Argument to the completion routine
-
FALSE); // Do not restore a suspended system
-
if (!bSuccess)
-
{
-
printf("SetWaitableTimer error.(%d)", GetLastError());
-
return;
-
}
-
-
// 回调函数
-
static void CALLBACK handler(
-
LPVOID lpArg, // Data value
-
DWORD dwTimerLowValue, // Timer low value
-
DWORD dwTimerHighValue ) // Timer high value */
-
{
-
const char* str = (const char*)lpArg;
-
printf("str=%s\n", str);
-
}
-
-
// 删除定时器
-
CancelWaitableTimer(timerId); // 取消激活
- CloseHandle(timerId); // 关闭句柄
在使用此种定时器时,导致阻塞中的函数select返回值不正常,debug版本下返回-1,这个与linux下
中断发生相似,比较好处理,只要重新调用select函数就好了。但是不能理解的是在release版本下,
它返回正常且select的返回值大于1,也就是多个可读写的描述字准备好了,实际并没有,导致
在下面的处理中调用accept函数时出现异常,不知道为什么,只好放弃使用此种定时器。
4. timer_create(linux)
// 创建定时器
int timer_create(clockid_t clockid, struct sigevent *sevp,
timer_t *timerid);
// 启动定时器
int timer_settime(timer_t timerid, int flags,
const struct itimerspec *new_value,
struct itimerspec *old_value);
// 删除定时器
int timer_delete(timer_t timerid);
- 示例1(超时启动线程调用回调函数)
点击(此处)折叠或打开
-
// 创建并启动定时器
-
timer_t timerid;
-
struct sigevent sev;
-
struct itimerspec its;
-
-
/* Create the timer */
-
memset(&sev, 0, sizeof(sev));
-
sev.sigev_notify = SIGEV_THREAD;
-
sev.sigev_notify_function = handler;
-
sev.sigev_value.sival_ptr = "test";
-
-
if (timer_create(CLOCKID, &sev, &timerid) == -1)
-
{
-
printf("timer_create error.(%s)", strerror(errno));
-
return;
-
}
-
-
its.it_value.tv_sec = 1;
-
its.it_value.tv_nsec = 0;
-
its.it_interval.tv_sec = its.it_value.tv_sec;
-
its.it_interval.tv_nsec = its.it_value.tv_nsec;
-
-
-
if (timer_settime(timerid, 0, &its, NULL) == -1)
-
{
-
printf("timer_settime error.(%s)", strerror(errno));
-
return;
-
}
-
-
// 回调函数(SIGEV_THREAD)
-
static void handler(union sigval si)
-
{
-
const char* str = si.sival_ptr;
-
printf("str=%s\n", str);
-
}
-
-
// 删除定时器
- timer_delete(timerId);
- 示例2(超时产生信号)
点击(此处)折叠或打开
-
// 创建并启动定时器
-
#define SIG SIGRTMIN
-
-
timer_t timerid;
-
struct sigevent sev;
-
struct itimerspec its;
-
sigset_t mask;
-
struct sigaction sa;
-
-
/* Establish handler for timer signal */
-
sa.sa_flags = SA_SIGINFO;
-
sa.sa_sigaction = handler;
-
sigemptyset(&sa.sa_mask);
-
if (sigaction(SIG, &sa, NULL) == -1)
-
{
-
printf("sigaction error.(%s)", strerror(errno));
-
return;
-
}
-
-
-
/* Block timer signal temporarily */
-
sigemptyset(&mask);
-
sigaddset(&mask, SIG);
-
if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1)
-
{
-
printf("sigprocmask error.(%s)", strerror(errno));
-
return;
-
}
-
-
-
/* Create the timer */
-
memset(&sev, 0, sizeof(sev));
-
sev.sigev_notify = SIGEV_SIGNAL;
-
sev.sigev_signo = SIG;
-
sev.sigev_value.sival_ptr = "test";
-
-
if (timer_create(CLOCKID, &sev, &timerid) == -1)
-
{
-
printf("timer_create error.(%s)", strerror(errno));
-
return;
-
}
-
-
-
/* Start the timer */
-
its.it_value.tv_sec = 1;
-
its.it_value.tv_nsec = 0;
-
its.it_interval.tv_sec = its.it_value.tv_sec;
-
its.it_interval.tv_nsec = its.it_value.tv_nsec;
-
-
-
if (timer_settime(timerid, 0, &its, NULL) == -1)
-
{
-
printf("timer_settime error.(%s)", strerror(errno));
-
return;
-
}
-
-
-
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
-
{
-
printf("sigprocmask error.(%s)", strerror(errno));
-
return;
-
}
-
-
// 信号处理函数
-
static void handler(int sig, siginfo_t *si, void *uc)
-
{
-
const char* str = si->si_value.sival_ptr;
-
printf("str=%s\n", str);
- }
※ 在solaris系统里好像不支持超时启动线程的方式启动timer, 如果下面这样设置调用timer_create函数,
此函数会返回错误-1.
sev.sigev_notify = SIGEV_THREAD