2017-04-24 64 views
1

我想要一个运行某些处理的方法,该处理最多持续一秒钟,休眠5分钟,然后重复。我也希望用户能够摆脱睡眠并优雅地退出。我希望它可以在一整天内运行,而不会消耗太多的系统资源。什么是最好的设计模式?如何在C#中正确实现可取消的长时间运行的线程?

这是我第一次尝试:

  • 我使用一个线程等待并做处理。我不确定是否应该使用线程,线程池线程或任务。我不认为它应该是一个任务,但因为没有涉及异步IO操作。我也不认为我应该使用定时器,因为我希望能够在不等待下一个间隔的情况下正常停止线程。
  • 我使用AutoResetEvents在两个线程之间发送信号。这允许内部代码在时间到或用户想要退出时运行。
  • 如果这个问题是重复的,我很抱歉。如果是这样,我找不到它。

这里是我的代码:

var areCanContinue = new AutoResetEvent(false); 
bool shouldContinue = true; 

var thread = new Thread(obj => 
{ 
    while (true) 
    { 
     areCanContinue.WaitOne(TimeSpan.FromMinutes(5)); 
     if (shouldContinue) 
     { 
      Process(); 
     } 
     else 
     { 
      break; 
     } 
    } 
}); 
thread.Start(); 

string response; 
do 
{ 
    Console.WriteLine("Press 'q' to quit"); 
    response = Console.ReadLine(); 
} while (response != "q"); 

shouldContinue = false; 
areCanContinue.Set(); 
+0

您是否熟悉计时器? – Media

+0

@Media,我在第二点提到了一个Timer。我不认为这是合适的,因为我希望能够在间隔期间取消过程。我不知道如何用Timer来做到这一点。 – user2023861

+0

@ user2023861要取消定时器,只需处理它。我的回答假设你想退出之前运行一些清理,但直接使用定时器是一个更好的解决方案 –

回答

4

任务不一定为I/O密集型操作。事实上,这是一个很好的用例为Task.Delay(其内部封装了一个定时器):

public static async Task ProcessAsync(CancellationToken cancellationToken) 
{ 
    try 
    { 
     while (true) 
     { 
      await Task.Delay(TimeSpan.FromMinutes(5), cancellationToken).ConfigureAwait(false); 

      Process(); 
     } 
    } 
    catch (TaskCanceledException) 
    { 
     // Cancellation requested, do whatever cleanup you need then exit gracefully 
    } 
} 

然后使用它:

var cancellationTokenSource = new CancellationTokenSource(); 

var task = ProcessAsync(cancellationTokenSource.Token); 

string response; 
do 
{ 
    Console.WriteLine("Press 'q' to quit"); 
    response = Console.ReadLine(); 
} while (response != "q"); 

cancellationTokenSource.Cancel(); 

task.Wait(); // Wait for the task to finish 

根据您的要求,您还可以直接使用定时器:

var timer = new Timer(_ => Process(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5)); 

string response; 
do 
{ 
    Console.WriteLine("Press 'q' to quit"); 
    response = Console.ReadLine(); 
} while (response != "q"); 

timer.Dispose(); // Stop the timer 
0

希望这会有所帮助。

class Program 
{ 
    static void Main(string[] args) 
    { 
     Operation op = new Operation(); 
     var tokenSource = new CancellationTokenSource(); 
     Task.Factory.StartNew(async() => await op.LongRunningApplication(tokenSource.Token)); 
     while(true) 
     { 
      Console.WriteLine("PRINT STOP for Cancellation..."); 
      var str = Console.ReadLine(); 
      if(string.Compare(str, "Stop", true) == 0) 
      { 
       Console.WriteLine("Cancellation Requested..."); 
       tokenSource.Cancel(); 
       Task.Delay(TimeSpan.FromSeconds(30)).Wait(); // Making Sure that It stops gracefully since this is console app 
       break; 
      } 
     } 
     Console.WriteLine("Completed"); 
    } 
} 

public class Operation 
{ 
    public async Task LongRunningApplication(CancellationToken token) 
    { 
     Console.WriteLine("Starting long Running application...."); 
     while (true) 
     { 
      await Task.Delay(1000); // Your Operation 
      Console.WriteLine("Wating..."); 
      for (int i = 0; i < 30; i++) 
      { 
       await Task.Delay(TimeSpan.FromSeconds(10)); // Wait For 5 Mins (10 sec , 30 intervals) 
       if (token != null && token.IsCancellationRequested) 
       { 
        Console.WriteLine("Stopping GraceFully.."); 
        return; 
       } 
      } 
     } 
    } 
} 
相关问题