如何在 C# 中正确实现可取消的 long-运行 线程?
How do I properly implement a cancellable, long-running thread in C#?
我想要一种方法,运行s 一些处理最多持续一秒钟,休眠 5 分钟,然后重复。我还希望用户能够从睡眠中醒来并优雅地退出。我希望它全天 运行 而不会消耗太多系统资源。最好的设计模式是什么?
这是我的第一次尝试:
- 我用一个线程来等待和做处理。我不确定我应该使用线程、线程池线程还是任务。我不认为这应该是一项任务,因为不涉及异步 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();
任务不一定用于 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
希望对您有所帮助。
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;
}
}
}
}
}
我想要一种方法,运行s 一些处理最多持续一秒钟,休眠 5 分钟,然后重复。我还希望用户能够从睡眠中醒来并优雅地退出。我希望它全天 运行 而不会消耗太多系统资源。最好的设计模式是什么?
这是我的第一次尝试:
- 我用一个线程来等待和做处理。我不确定我应该使用线程、线程池线程还是任务。我不认为这应该是一项任务,因为不涉及异步 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();
任务不一定用于 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
希望对您有所帮助。
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;
}
}
}
}
}