Пробуждение потока каждые n секунд

#c# #.net #wpf #multithreading #thread-safety

#c# #.net #wpf #многопоточность #потокобезопасность

Вопрос:

Я пишу приложение WPF с использованием C #, и мне нужна некоторая помощь с обработкой потоков. У меня есть три класса, каждый из которых должен запускать задачу каждые n секунд в своем собственном потоке. Вот как я это сделал с Qt4:

 class myThread : public QThread
{
    void run (void)
    {
        while (true)
        {
            mMutex.lock();
            mWaitCondition.wait (amp;mMutex);

            // Some task

            mMutex.unlock();
        }
    }

    void wait (int timeout)
    {
        // For shutdown purposes
        if (mMutex.tryLock (timeout))
            mMutex.unlock();
    }

    void wake (void)
    {
        mWaitCondition.wakeAll();
    }
}

// Some other class has a timer which ticks
// every n seconds calling the wake function
// of the myThread class.
  

Что я получаю от этого, так это контролируемый интервал обновления. Итак, если я обновляю 60 раз в секунду, если код медленный и может выполняться только 30 раз в секунду, у него нет проблем с этим, но он никогда не будет выполняться более 60 раз в секунду. Он также не будет запускать один и тот же код более одного раза одновременно. Какой самый простой способ реализовать это на C #?

Ответ №1:

Вместо этого вам следует использовать Timer .

Прочитайте эту статью для получения подробной информации или эту для более компактного объяснения.

Ответ №2:

.NET Reactive Extensions допускают сложную асинхронную композицию событий на основе времени — это, вероятно, хорошая отправная точка для поведения, связанного со временем.

Ответ №3:

Вы можете использовать там классы для этого

 using System;
using System.Timers;
using System.Threading;

public class ClassTask
{
    System.Timers.Timer timer = null;

    public bool IsRunning { get; set; }

    public DateTime LastRunTime { get; set; }

    public bool IsLastRunSuccessful { get; set; }

    public double Interval { get; set; }

    public bool Stopped { get; set; }

    public ClassTask(double interval)
    {
        this.Interval = interval;
        this.Stopped = false;
        timer = new System.Timers.Timer(this.Interval);
        timer.Elapsed  = new ElapsedEventHandler(timer_Elapsed);
        timer.Enabled = true;
    }
    public void Start()
    {
        this.Stopped = false;
        this.StartTask();
    }

    public void Stop()
    {
        this.Stopped = true;
    }

    private void StartTask()
    {
        if (!this.Stopped)
        {
            //Thread thread = new Thread(new ThreadStart(Execute));
            //thread.Start();
            Execute();
        }
    }

    private void Execute()
    {
        try
        {
            this.IsRunning = true;
            this.LastRunTime = DateTime.Now;

            // Write code here

            this.IsLastRunSuccessful = true;
        }
        catch
        {
            this.IsLastRunSuccessful = false;
        }
        finally
        {
            this.IsRunning = false;
        }
    }

    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        if (!this.IsRunning)
            StartTask();
    }
}

using System;
using System.Data;
using System.Configuration;

public class ClassTaskScheduler
{
    ClassTask task = null;

    public ClassTaskScheduler()
    {
        this.task = new ClassTask(60000);
    }

    public void StartTask()
    {
        this.task.Start();
    }

    public void StopTask()
    {
        this.task.Stop();
    }
}
  

В global.asax или где вы хотите вызвать это

 void Application_Start(object sender, EventArgs e) 
    {
        // Code that runs on application startup
        ClassTaskScheduler _scheduler = new ClassTaskScheduler();
        _scheduler.StartTask();
    }

    void Application_End(object sender, EventArgs e) 
    {
        //  Code that runs on application shutdown
        ClassTaskScheduler _scheduler = new ClassTaskScheduler();
        _scheduler.StopTask();
    }
  

Вы можете использовать функцию Execute() для выполнения задачи в заданный интервал времени….

Ответ №4:

Эквивалентом в .NET было бы использование ManualResetEvent . Используйте WaitOne метод с таймаутом, чтобы вызвать ожидание. Это также может использоваться в качестве механизма завершения работы. Самое приятное в этом подходе то, что он прост, все выполняется одним потоком, и один и тот же код не может выполняться параллельно (потому что все это в одном потоке).

 class myThread
{
  private ManualResetEvent m_WaitHandle = new ManualResetEvent(false);

  public myThread
  {
    new Thread(Run).Start();
  }

  public void Shutdown()
  {
    m_WaitHandle.Set(); // Signal the wait handle.
  }

  private void Run()
  {
    while (!m_WaitHandle.WaitOne(INTERVAL)) // The waiting happens here.
    {
      // Some task
    }
    // If execution gets here then the wait handle was signaled from the Shutdown method.
  }
}