C# 每 X 分钟运行一个线程,但前提是该线程尚未运行 [英] C# run a thread every X minutes, but only if that thread is not running already

查看:20
本文介绍了C# 每 X 分钟运行一个线程,但前提是该线程尚未运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 C# 程序需要每 X 分钟分派一个线程,但前提是之前分派的线程(从 X 分钟开始)当前不在运行.

I have a C# program that needs to dispatch a thread every X minutes, but only if the previously dispatched thread (from X minutes) ago is not currently still running.

一个普通的 Timer 单独是行不通的(因为它每 X 分钟调度一个事件,不管之前调度的进程是否已经完成).

A plain old Timer alone will not work (because it dispatches an event every X minutes regardless or whether or not the previously dispatched process has finished yet).

要分派的进程在执行其任务所需的时间方面变化很大 - 有时可能需要一秒钟,有时可能需要几个小时.如果它从上次启动时仍在处理,我不想再次启动该进程.

The process that's going to get dispatched varies wildly in the time it takes to perform it's task - sometimes it might take a second, sometimes it might take several hours. I don't want to start the process again if it's still processing from the last time it was started.

谁能提供一些可用的 C# 示例代码?

Can anyone provide some working C# sample code?

推荐答案

在我看来,这种情况的方法是使用 System.ComponentModel.BackgroundWorker 类,然后简单地检查它的 IsBusy 属性每次你想要调度(或不调度)新线程.代码非常简单;这是一个例子:

In my opinion the way to go in this situation is to use System.ComponentModel.BackgroundWorker class and then simply check its IsBusy property each time you want to dispatch (or not) the new thread. The code is pretty simple; here's an example:

class MyClass
{    
    private BackgroundWorker worker;

    public MyClass()
    {
        worker = new BackgroundWorker();
        worker.DoWork += worker_DoWork;
        Timer timer = new Timer(1000);
        timer.Elapsed += timer_Elapsed;
        timer.Start();
    }

    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        if(!worker.IsBusy)
            worker.RunWorkerAsync();
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        //whatever You want the background thread to do...
    }
}

在这个例子中,我使用了 System.Timers.Timer,但我相信它也适用于其他计时器.BackgroundWorker 类还支持进度报告和取消,并使用事件驱动模型与调度线程通信,因此您不必担心 volatile 变量等......

In this example I used System.Timers.Timer, but I believe it should also work with other timers. The BackgroundWorker class also supports progress reporting and cancellation, and uses event-driven model of communication with the dispatching thread, so you don't have to worry about volatile variables and the like...

编辑

以下是更详细的示例,包括取消和进度报告:

Here's more elaborate example including cancelling and progress reporting:

class MyClass
{    
    private BackgroundWorker worker;

    public MyClass()
    {
        worker = new BackgroundWorker()
        {
            WorkerSupportsCancellation = true,
            WorkerReportsProgress = true
        };
        worker.DoWork += worker_DoWork;
        worker.ProgressChanged += worker_ProgressChanged;
        worker.RunWorkerCompleted += worker_RunWorkerCompleted;

        Timer timer = new Timer(1000);
        timer.Elapsed += timer_Elapsed;
        timer.Start();
    }

    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        if(!worker.IsBusy)
            worker.RunWorkerAsync();
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker w = (BackgroundWorker)sender;

        while(/*condition*/)
        {
            //check if cancellation was requested
            if(w.CancellationPending)
            {
                //take any necessary action upon cancelling (rollback, etc.)

                //notify the RunWorkerCompleted event handler
                //that the operation was cancelled
                e.Cancel = true; 
                return;
            }

            //report progress; this method has an overload which can also take
            //custom object (usually representing state) as an argument
            w.ReportProgress(/*percentage*/);

            //do whatever You want the background thread to do...
        }
    }

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        //display the progress using e.ProgressPercentage and/or e.UserState
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if(e.Cancelled)
        {
            //do something
        }
        else
        {
            //do something else
        }
    }
}

然后,为了取消进一步的执行,只需调用 worker.CancelAsync().请注意,这完全是用户处理的取消机制(它不支持线程中止或任何类似的开箱即用).

Then, in order to cancel further execution simply call worker.CancelAsync(). Note that this is completely user-handled cancellation mechanism (it does not support thread aborting or anything like that out-of-the-box).

这篇关于C# 每 X 分钟运行一个线程,但前提是该线程尚未运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆