本项目中并不是运用linux系统自带的cron触发功能,而是自己实现cron表达式时间触发机制,代码是对busybox中的源码进行裁剪:
一、Cron表达式基础
1、cron表达式
顺序 | 秒 | 分钟 | 小时 | 日期 | 月份 | 星期 | 年(可选) |
取值 | 0-59 | 0-59 | 0-23 | 1-30(31) | 1-12 | 1-7 |
|
允许特殊字符 | , - * / | , - * / | , - * / | , - * / ? L W C | , - * / | , - * / L # C | 1970-2099 , - * / |
2、每个字段含义
*:代表所有可能的值
-:指定范围
,:列出枚举 例如在分钟里,"5,15"表示5分钟和20分钟触发
/:指定增量 例如在分钟里,"3/15"表示从3分钟开始,没隔15分钟执行一次
?:表示没有具体的值,使用?要注意冲突
L:表示last,例如星期中表示7或SAT,月份中表示最后一天31或30,6L表示这个月倒数第6天,FRIL表示这个月的最后一个星期五
W:只能用在月份中,表示最接近指定天的工作日
#:只能用在星期中,表示这个月的第几个周几,例如6#3表示这个月的第3个周五
3、示例
0 * * * * ? 每1分钟触发一次
0 0 * * * ? 每天每1小时触发一次
0 0 10 * * ? 每天10点触发一次
0 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
0 30 9 1 * ? 每月1号上午9点半
0 15 10 15 * ? 每月15日上午10:15触发
*/5 * * * * ? 每隔5秒执行一次
0 */1 * * * ? 每隔1分钟执行一次
0 0 5-15 * * ? 每天5-15点整点触发
0 0/3 * * * ? 每三分钟触发一次
0 0 0 1 * ? 每月1号凌晨执行一次
二、Cron表达式时间触发代码运用
本项目中并不是运用linux系统自带的cron触发功能,而是自己实现cron表达式触发机制,代码是对busybox中的源码进行裁剪:
功能:到某一个时间点触发一个时间:
直接上代码:
从linux系统 busybox源码中裁剪出的代码:
typedef struct CronLine
{
/* ordered by size, not in natural order. makes code smaller: */
char cl_Dow[7]; /* 0-6, beginning sunday */
char cl_Mons[13]; /* 1-12 */
char cl_Hrs[24]; /* 0-23 */
char cl_Days[32]; /* 1-31 */
char cl_Mins[60]; /* 0-59 */
} CronLine;
static void ParseField(char *ary, int modvalue, char *ptr)
{
char *base = ptr;
int n1 = -1;
int n2 = -1;
while (1)
{
int skip = 0;
if (*ptr == '*')
{
n1 = 0; /* everything will be filled */
n2 = modvalue - 1;
skip = 1;
++ptr;
}
else if (isdigit(*ptr)) //是否为十进制数字字符
{
char *endp;
if (n1 < 0)
{
n1 = strtol(ptr, &endp, 10); //将字符串转换为长整型数(long)
}
else
{
n2 = strtol(ptr, &endp, 10);
}
ptr = endp; /* gcc likes temp var for &endp */
skip = 1;
}
/* handle optional range '-' */
if (skip == 0)
{
goto err;
}
if (*ptr == '-' && n2 < 0)
{
++ptr;
continue;
}
/*
* collapse single-value ranges, handle skipmark, and fill
* in the character array appropriately.
*/
if (n2 < 0)
{
n2 = n1;
}
if (*ptr == '/')
{
char *endp;
skip = strtol(ptr + 1, &endp, 10);
ptr = endp; /* gcc likes temp var for &endp */
}
/*
* fill array, using a failsafe is the easiest way to prevent
* an endless loop
*/
{
int s0 = 1;
int failsafe = 1024;
--n1;
do
{
n1 = (n1 + 1) % modvalue;
if (--s0 == 0)
{
ary[n1 % modvalue] = 1;
s0 = skip;
}
if (--failsafe == 0)
{
goto err;
}
}
while (n1 != n2);
}
if (*ptr != ',')
{
break;
}
++ptr;
n1 = -1;
n2 = -1;
}
if (*ptr)
{
err:
PRINT_LOG(" parse error at %s\n", base);
return;
}
}
static void FixDayDow(CronLine *line)
{
unsigned i;
int weekUsed = 0;
int daysUsed = 0;
for (i = 0; i < ARRAY_SIZE(line->cl_Dow); ++i)
{
if (line->cl_Dow[i] == 0)
{
weekUsed = 1;
break;
}
}
for (i = 0; i < ARRAY_SIZE(line->cl_Days); ++i)
{
if (line->cl_Days[i] == 0)
{
daysUsed = 1;
break;
}
}
if (weekUsed != daysUsed)
{
if (weekUsed)
memset(line->cl_Days, 0, sizeof(line->cl_Days));
else /* daysUsed */
memset(line->cl_Dow, 0, sizeof(line->cl_Dow));
}
}
static void Sync_CronTime(char *CronStr, UINT strLen, CronLine *cronLine)
{
char *tokens[5];
BYTE i;
char CronStrTemp[48];
char *start;
char *pos;
memset(CronStrTemp, 0, sizeof(CronStrTemp));
memcpy(CronStrTemp, CronStr, strLen);
start = CronStrTemp;
for(i = 0; i < 4; i++)
{
pos = strchr(start, ' ');
if(pos == NULL)
{
return;
}
tokens[i] = start;
tokens[i][pos-start] = '\0';
start = pos + 1;
}
tokens[4] = start;
memset((char *)cronLine, 0, sizeof(CronLine));
ParseField(cronLine->cl_Mins, 60, tokens[0]);
ParseField(cronLine->cl_Hrs, 24, tokens[1]);
ParseField(cronLine->cl_Days, 32, tokens[2]);
ParseField(cronLine->cl_Mons, 13, tokens[3]);
ParseField(cronLine->cl_Dow, 7, tokens[4]);
FixDayDow(cronLine);
}
应用代码:应用代码:
//定时线程,不同时间点触发运行任务策略
UINT RTC_Strategy_TimePointSwitch(void)
{
BYTE iLoop, cronLoop;
CronLine cronLine;
Strategy *pStrategy;
ScaleTime pTime;
INT CurStrategyID,CurCronID;
UINT Ret = ERR_NO_DATA;
Sys_GetTime((ScaleTime *)&pTime); //获取当前时间
if((pTime.Hour >= 18) &&( pTime.Hour < 20)) //时间在18-20点,运行18点的任务
{
pTime.Hour = 18;
}
else if((pTime.Hour >= 20) &&( pTime.Hour < 22)) //时间在20-22点,运行20点的任务
{
pTime.Hour = 20;
}
else if((pTime.Hour >= 22) &&( pTime.Hour<=23))//时间在22-23点,运行22点的任务
{
pTime.Hour = 22;
}
else if((pTime.Hour >= 0) &&( pTime.Hour< 2)) //时间在0-2点,运行0点的任务
{
pTime.Hour = 0;
}
for(iLoop = 0; iLoop < MAX_STRATEGY_NUM; iLoop++) //任务编号越大,优先级越高
{
if(STG_Open(iLoop, CRON_O_RDONLY) == NULL)
{
continue;
}
pStrategy = STG_Read(iLoop);
if(pStrategy == NULL)
{
continue;
}
for(cronLoop = 0; cronLoop < pStrategy->CronSum; cronLoop++) //多个时间点
{
Sync_CronTime((char *)pStrategy->CronData[cronLoop].CronStr, pStrategy->CronData[cronLoop].Cron_Strlen, (CronLine *)&cronLine);
if(cronLine.cl_Mons[pTime.Mon] && cronLine.cl_Days[pTime.Day] && cronLine.cl_Hrs[pTime.Hour]) //&&cronLine.cl_Mins[pTime.Min]
{
CurStrategyID = iLoop;
CurCronID = cronLoop;
Ret = ERR_NULL;
break;
}
}
}
if( Ret == ERR_NULL)
{
if((g_CurStrategyID == CurStrategyID) && (g_CurCronID == CurCronID))
{
Ret = ERR_NO_DATA;
}
else
{
g_CurStrategyID = CurStrategyID;
g_CurCronID = CurCronID;
}
}
return Ret;
}