本项目中并不是运用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;
}