使用thread.sleep时如何在无限循环中执行多个任务

时间:2017-01-15 18:18:06

标签: c# .net multithreading console-application

我想每天早上4点执行.exe。我使用以下代码完成了这项工作。

Directory.Delete(folder_path, recursive: true);

现在我想再执行一项任务,例如每晚凌晨1点删除特定文件夹和子文件夹。因此,对于删除,我将使用像

这样的代码
{{1}}

我应该使用相同的无限循环还是以其他方式实现它?

4 个答案:

答案 0 :(得分:4)

您不应该使用Thread.Sleep进行计时。尽量避免使用Thread.Sleep。如果中止该线程,则只能中断睡眠。更好的方法是ManualResetEvent.Wait()可以通过设置来中断。

我的建议是,使用计时器:

创建一个正在检查作业列表的计时器。添加下一次在作业上执行。计时器不会阻止MainThread,因此您可以安全地终止该应用程序。您可以每分钟甚至更高的时间检查作业(间隔)。

<强>伪!!

class MyJob
{
    public DateTime ExecuteTime { get; set; }
    public Action Action { get; set; }
}

List<MyJob> Jobs = new List<MyJob>();

public void TimerCallback(object sender, EventArgs e)
{
    foreach (var job in Jobs)
    {
        if (job.ExecuteTime <= DateTime.Now)
        {
            try
            {
                job.Action();
            }
            catch(Exception exception)
            {
                // log the exception..
            }
            finally
            {
                job.ExecuteTime = job.ExecuteTime.Add(TimeSpan.FromDays(1));
            }
        }
    }
}

// this AddJob checks if the first execute should be today or tomorrow
public void AddJob(TimeSpan executeOn, Action action)
{
    var now = DateTime.Now;

    var firstExec = new DateTime(now.Year, now.Month, now.Day, 4, 0, 0);

    if (firstExec < now)  // time for today is already passed, next day..
        firstExec = firstExec.Add(TimeSpan.FromDays(1));

    Jobs.Add(new MyJob { ExecuteTime = firstExec, Action = action });
}

public void Add()
{
    // Add the jobs.
    AddJob(new TimeSpan(4, 0, 0), RunMyJob);
    AddJob(new TimeSpan(5, 0, 0), RunMyJob2);
}

public void RunMyJob()
{
    // delete or move, whatever...
}

public void RunMyJob2()
{
    // delete or move, whatever...
}

答案 1 :(得分:2)

如果你所做的只是安排单个.exe,你可以使用Windows任务计划程序 - 它比自己尝试自己要容易得多。如果您需要在几个不同的时间完成多个任务,则可以创建多个.exes。 (抱歉要简短,我是在电话上写的。)

答案 2 :(得分:2)

我会使用Microsoft的Reactive Framework(NuGet“System.Reactive”)。

然后你可以编写这个方便的助手方法:

public IDisposable ScheduleDaily(TimeSpan when, Action what)
{
    var now = DateTime.Now;
    var schedule = now.Date.Add(when);
    if (schedule < now)
    {
        schedule = schedule.AddDays(1.0);
    }

    return
        Observable
            .Timer(schedule, TimeSpan.FromDays(1.0))
            .Subscribe(_ => what());
}

要打电话就行:

IDisposable runSample = ScheduleDaily(TimeSpan.FromHours(4.0),
    () => Process.Start("sample.exe"));

IDisposable deleteFolders = ScheduleDaily(TimeSpan.FromHours(1.0),
    () => Directory.Delete(folder_path, recursive: true));

ScheduleDaily会返回一个方便的IDisposable,您可以.Dispose()停止计时器。

无需线程或休眠。非常简单。

答案 3 :(得分:1)

Thread.Sleep()导致当前线程进入休眠状态,因此线程不会再做任何事情,直到它完成睡眠(除非你打断它或其他东西)。

所以,如果你这样做,你只需要更多的线程。

var scheduleLoopAction = new Action<int, int, string>((int hour, int minute, string processName) =>
{
    while (true)
    {
        var now = DateTime.Now;
        var schedule = new DateTime(now.Year, now.Month, now.Day, hour, minute, 00);
        if (schedule < now) schedule = schedule.AddDays(1);

        System.Threading.Thread.Sleep(schedule.Subtract(now));

        System.Diagnostics.Process.Start(processName);
    }
});

((new System.Threading.Thread(() => { scheduleLoopAction(4, 0, "sample.exe"); }))).Start();
((new System.Threading.Thread(() => { scheduleLoopAction(1, 0, "sample2.exe"); }))).Start();

这可能不是实现目标的最佳方式,但我认为你想要的东西就像问题中的内容一样。

请注意,线程调用不会阻止,因此此方法将立即完成(与问题中的示例不同,它将永远存在)。如果您希望它阻止,您可以在当前线程中运行最后一个计划,例如

((new System.Threading.Thread(() => { scheduleLoopAction(4, 0, "sample.exe"); }))).Start();
scheduleLoopAction(1, 0, "sample2.exe");  // Runs in current thread