如何取消在C#中执行多个任务的等待任务
How to cancel await Task that perform multiple task in C#
我在空闲时间有一个功能,在某个时间间隔,例如每 30 秒,它将对硬件执行一次状态轮询。
方法名称是public static async Task PollCurrentHardwareStatus()
,在这个方法中,它会检查每个硬件的状态,例如。我有 4 个设备来获取连接状态(打印机模块、现金模块、硬币模块、终端模块)。
如果public触摸主屏幕,它将转到下一页,我需要取消投票状态。如何在等待任务中取消设备的轮询状态?
我已经通过了 Cancel an Async Task or a List of Tasks (C#),但我似乎不知道将 CancellationToken 放在哪里。
我在 PollCurrentHardwareStatus
的代码:-
public static async Task PollCurrentHardwareStatus()
{
try
{
//POLLING CARD READER
if (GlobVars.HwIDTech.Enabled)
{
if (IDTechDevice.PingForReply())
{
LogEvents($"[App] Terminal OK.", EventLogEntryType.Information);
AppDeviceStatus.strIDTechStatus = StatusMessageIDTech.strSuccessID;
}
else
{
LogEvents($"[App] IDTechDevice: Not found/Disconnected", EventLogEntryType.Information);
AppDeviceStatus.strIDTechStatus = StatusMessageIDTech.strErrorID;
}
}
//POLLING PRINTER
if (GlobVars.HwCustom.Enabled)
{
string description = string.Empty;
int status = 0;
PrintMain.PrinterGetStatus(ref description, ref status);
if (status == 0)
{
AppDeviceStatus.strPrinterStatus = StatusMessagePrinter.strSuccessID;
}
else
{
LogEvents($"[App] Printer error: {description}", EventLogEntryType.Information);
AppDeviceStatus.strPrinterStatus = StatusMessagePrinter.strErrorID;
}
}
//POLLING CASH COIN MODULE
if (GlobVars.HwB2B.Enabled && GlobVars.HwBCR.Enabled)
{
string B2BStatus = await CCMain.GetCurrentDeviceStatus();
if (B2BStatus == "DISABLED")
{
AppDeviceStatus.strB2BStatus = StatusMessageB2B.strSuccessID;
LogEvents($"[App] Poll B2B device: Status - OK.", EventLogEntryType.Information);
}
else
{
LogEvents($"[App] Poll B2B device: Status - {B2BStatus}.", EventLogEntryType.Information);
AppDeviceStatus.strB2BStatus = StatusMessageB2B.strErrorID;
}
if (ModuleCoins.OpenConnection())
{
await ModuleCoins.PerformSelfTest();
AppDeviceStatus.strBCRStatus = StatusMessageBCR.strSuccessID;
}
else
{
AppDeviceStatus.strBCRStatus = StatusMessageBCR.strErrorID;
}
}
UpdateErrorStatus();
}
catch (Exception ex)
{
LogEvents($"[App] Poll hardware status : Ex-{ex.Message}. Stack Trace-{ex.StackTrace}", EventLogEntryType.Error);
}
await Task.Delay(100);
}
我认为您可以通过调用 PollCurrentHardwareStatus() 的方法创建 CancellationTokenSource。请检查以下示例:
在 PollCurrentHardwareStatus 方法中添加 CancellationTokenSource 作为参数
public static async Task PollCurrentHardwareStatus(CancellationToken cts)
{
// your logic code
// ...............
}
创建一个 CancellationTokenSource 并在您的页面上调用它 class:
public class Page
{
private CancellationTokenSource cancellationTokenSource;
public Page()
{
cancellationTokenSource = new CancellationTokenSource();
}
public async void CallPoll()
{
await PollCurrentHardwareStatus(cancellationTokenSource.Token);
}
public void OnCancelPoll(object sender, EventArgs e)
{
cancellationTokenSource.Cancel();
}
}
根据 MSDN:Cancellation in managed threads
Cancellation is cooperative and is not forced on the listener. The
listener determines how to gracefully terminate in response to a
cancellation request.
您必须创建 PollCurrentHardwareStatus
的重载,将 CancellationToken 对象作为输入。函数应该定期检查是否请求取消并优雅地取消函数。
这里面有几个问题:什么是reqularly?请求取消时该怎么办。
答案符合您的要求。这取决于中断的原因,您是否应该在 50 毫秒内取消,或者取消是否需要一秒钟。例如,如果您的流程在操作员第一次触摸您的屏幕时被中断,则该操作员可能愿意在屏幕响应之前等待半秒钟。但是,如果每次操作员键入一个字母时您的过程都被中断,那么一秒钟取消可能会很烦人。
因此,您应该多久检查一次取消的问题取决于使用情况。
async Task PollCurrentHardwareStatus(CancellatinToken token)
{
token.ThrowIfCancellationRequested();
DoSomeShortProcessing();
token.ThrowIfCancellationRequested();
DoSomeOtherProcessing();
token.ThrowIfcancellationRequested();
等等
如果您调用一个处理时间较长的函数,就会出现问题。最好的办法是将 token
传递给另一个进程:
LongProcessingFunction(token);
其他函数应该定期检查令牌。
优雅地取消取决于此。
如果不能更改其他功能,则无法保证正确快速的取消。
async-await 在这方面帮不了你。由创建可等待函数的程序员提供接受 CancellationToken 的版本。
您会发现所有可等待的基本功能(读/写文件、从数据库或互联网获取信息等)都有一个接受 CancellationToken 的版本。
您可以启动一个线程并在请求取消时终止该线程,但这是相当危险的,因为您不知道线程终止时对象的状态。我不建议这样做。
我在空闲时间有一个功能,在某个时间间隔,例如每 30 秒,它将对硬件执行一次状态轮询。
方法名称是public static async Task PollCurrentHardwareStatus()
,在这个方法中,它会检查每个硬件的状态,例如。我有 4 个设备来获取连接状态(打印机模块、现金模块、硬币模块、终端模块)。
如果public触摸主屏幕,它将转到下一页,我需要取消投票状态。如何在等待任务中取消设备的轮询状态?
我已经通过了 Cancel an Async Task or a List of Tasks (C#),但我似乎不知道将 CancellationToken 放在哪里。
我在 PollCurrentHardwareStatus
的代码:-
public static async Task PollCurrentHardwareStatus()
{
try
{
//POLLING CARD READER
if (GlobVars.HwIDTech.Enabled)
{
if (IDTechDevice.PingForReply())
{
LogEvents($"[App] Terminal OK.", EventLogEntryType.Information);
AppDeviceStatus.strIDTechStatus = StatusMessageIDTech.strSuccessID;
}
else
{
LogEvents($"[App] IDTechDevice: Not found/Disconnected", EventLogEntryType.Information);
AppDeviceStatus.strIDTechStatus = StatusMessageIDTech.strErrorID;
}
}
//POLLING PRINTER
if (GlobVars.HwCustom.Enabled)
{
string description = string.Empty;
int status = 0;
PrintMain.PrinterGetStatus(ref description, ref status);
if (status == 0)
{
AppDeviceStatus.strPrinterStatus = StatusMessagePrinter.strSuccessID;
}
else
{
LogEvents($"[App] Printer error: {description}", EventLogEntryType.Information);
AppDeviceStatus.strPrinterStatus = StatusMessagePrinter.strErrorID;
}
}
//POLLING CASH COIN MODULE
if (GlobVars.HwB2B.Enabled && GlobVars.HwBCR.Enabled)
{
string B2BStatus = await CCMain.GetCurrentDeviceStatus();
if (B2BStatus == "DISABLED")
{
AppDeviceStatus.strB2BStatus = StatusMessageB2B.strSuccessID;
LogEvents($"[App] Poll B2B device: Status - OK.", EventLogEntryType.Information);
}
else
{
LogEvents($"[App] Poll B2B device: Status - {B2BStatus}.", EventLogEntryType.Information);
AppDeviceStatus.strB2BStatus = StatusMessageB2B.strErrorID;
}
if (ModuleCoins.OpenConnection())
{
await ModuleCoins.PerformSelfTest();
AppDeviceStatus.strBCRStatus = StatusMessageBCR.strSuccessID;
}
else
{
AppDeviceStatus.strBCRStatus = StatusMessageBCR.strErrorID;
}
}
UpdateErrorStatus();
}
catch (Exception ex)
{
LogEvents($"[App] Poll hardware status : Ex-{ex.Message}. Stack Trace-{ex.StackTrace}", EventLogEntryType.Error);
}
await Task.Delay(100);
}
我认为您可以通过调用 PollCurrentHardwareStatus() 的方法创建 CancellationTokenSource。请检查以下示例:
在 PollCurrentHardwareStatus 方法中添加 CancellationTokenSource 作为参数
public static async Task PollCurrentHardwareStatus(CancellationToken cts)
{
// your logic code
// ...............
}
创建一个 CancellationTokenSource 并在您的页面上调用它 class:
public class Page
{
private CancellationTokenSource cancellationTokenSource;
public Page()
{
cancellationTokenSource = new CancellationTokenSource();
}
public async void CallPoll()
{
await PollCurrentHardwareStatus(cancellationTokenSource.Token);
}
public void OnCancelPoll(object sender, EventArgs e)
{
cancellationTokenSource.Cancel();
}
}
根据 MSDN:Cancellation in managed threads
Cancellation is cooperative and is not forced on the listener. The listener determines how to gracefully terminate in response to a cancellation request.
您必须创建 PollCurrentHardwareStatus
的重载,将 CancellationToken 对象作为输入。函数应该定期检查是否请求取消并优雅地取消函数。
这里面有几个问题:什么是reqularly?请求取消时该怎么办。
答案符合您的要求。这取决于中断的原因,您是否应该在 50 毫秒内取消,或者取消是否需要一秒钟。例如,如果您的流程在操作员第一次触摸您的屏幕时被中断,则该操作员可能愿意在屏幕响应之前等待半秒钟。但是,如果每次操作员键入一个字母时您的过程都被中断,那么一秒钟取消可能会很烦人。
因此,您应该多久检查一次取消的问题取决于使用情况。
async Task PollCurrentHardwareStatus(CancellatinToken token)
{
token.ThrowIfCancellationRequested();
DoSomeShortProcessing();
token.ThrowIfCancellationRequested();
DoSomeOtherProcessing();
token.ThrowIfcancellationRequested();
等等
如果您调用一个处理时间较长的函数,就会出现问题。最好的办法是将 token
传递给另一个进程:
LongProcessingFunction(token);
其他函数应该定期检查令牌。 优雅地取消取决于此。 如果不能更改其他功能,则无法保证正确快速的取消。
async-await 在这方面帮不了你。由创建可等待函数的程序员提供接受 CancellationToken 的版本。
您会发现所有可等待的基本功能(读/写文件、从数据库或互联网获取信息等)都有一个接受 CancellationToken 的版本。
您可以启动一个线程并在请求取消时终止该线程,但这是相当危险的,因为您不知道线程终止时对象的状态。我不建议这样做。