cron如何在内部安排工作?

Jé *_*eue 41 unix linux cron scheduler crontab

"现代" cron守护进程如何在内部安排工作?有些人crond习惯于每隔一段时间安排一次跑步at.所以在写完crontab之后,会crond:

  1. 解析所有未来事件的crontab和间隔的睡眠?
  2. 每分钟轮询一个聚合的crontab数据库,以确定当前时间是否与计划模式匹配?
  3. 其他?

谢谢,

Jé *_*eue 55

在这个问题上听到了一些蟋蟀.好的OLFC和一些离散的事件模拟论文和维基百科:

http://en.wikipedia.org/wiki/Cron#Multi-user_capability

该cron使用的算法如下:

  1. 在启动时,在所有帐户持有者的主目录中查找名为.crontab的文件.
  2. 对于找到的每个crontab文件,确定将来下次运行每个命令的时间.
  3. 将这些命令放在Franta-Maly事件列表中,并附上相应的时间和"五字段"时间说明符.
  4. 进入主循环:
    1. 检查队列头部的任务条目,计算将来运行的距离.
    2. 睡了一段时间.
    3. 在唤醒和验证正确时间后,使用创建它的用户的权限在队列的头部(后台)执行任务.
    4. 确定将来的下一次运行此命令并将其放回到当时的事件列表中

  • 基于`cron`的`man`页面,看起来它每分钟都会唤醒以检查它是否应该运行一个作业:"然后cron每分钟唤醒,检查所有存储的crontabs,检查每个命令以查看它是否应该在当前分钟运行." 这是来自安装在Debian上的Vixie Cron(由Paul Vixie编写).我认为你所描述的算法在每分钟唤醒时使用的成本太高. (3认同)
  • @TylerBrock,我相信OP指的是Franta,WR和Kurt Maly.模拟事件集的有效数据结构.明尼苏达大学,http://staff.ii.pw.edu.pl/~gjb/aal/index_lists.pdf. (3认同)

Anm*_*ggi 9

我写了一篇博客文章来描述它。
从那里引用相关文本:

  • 我们可以有一个有限的线程池,它将通过从PriorityBlockingQueue优先级为 的(线程安全堆)中提取它们来执行所有任务job.nextExecutionTime()
  • 这意味着该堆的顶部元素将始终是最快触发的元素。
  • 我们将遵循标准的线程池生产者-消费者模式。
  • 我们将有一个线程在无限循环中运行,并在从队列中使用新作业后将新作业提交到线程池。让我们称之为QueueConsumerThread
void goToSleep(job, jobQueue){
    jobQueue.push(job);
    sleep(job.nextExecutionTime() - getCurrentTime());
}

void executeJob(job, jobQueue){
    threadpool.submit(job); // async call
    if (job.isRecurring()) {
        job = job.copy().setNextExecutionTime(getCurrentTime() + job.getRecurringInterval());
        jobQueue.add(job);
    }
}

@Override
void run(){
    while(true)
    {
        job = jobQueue.pop()
        if(job.nextExecutionTime() > getCurrentTime()){
            // Nothing to do
            goToSleep(job, jobQueue)
        }
        else{
            executeJob(job, jobQueue)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 还有一个线程将监视 crontab 文件中是否有任何新作业添加,并将它们推送到队列中。
  • 让我们称之为QueueProducerThread
@Override
void run()
{
    while(true)
    {
        newJob = getNewJobFromCrontabFile() // blocking call
        jobQueue.push(newJob)
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 但是,这有一个问题:
    • 想象一下,Thread1 正在睡觉,一个小时后会醒来。
    • 与此同时,一个新任务到达,它应该每分钟运行一次。
    • 这个新任务要到一个小时后才能开始执行。
  • 为了解决这个问题,我们可以让 ProducerThread 从它的睡眠中强行唤醒 ConsumerThread,只要新任务必须比队列中的前端任务运行得早:
@Override
void run()
{
    while(true)
    {
        newJob = getNewJobFromCrontabFile() // blocking call
        jobQueue.push(newJob)
        if(newJob == jobQueue.peek())
        {
            // The new job is the one that will be scheduled next.
            // So wakeup consumer thread so that it does not oversleep.
            consumerThread.interrupt()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这可能不是 cron 在内部实现的方式。但是,这是我能想到的最佳解决方案。它不需要轮询并且所有线程在需要做任何工作之前都处于休眠状态。