我通过一种方法获得Uploader
课程 - Upload
public static int Upload(string endpoint,object objectToBeUploaded)
{
Source.Token.ThrowIfCancellationRequested();
var repos = new UploadRepository(endpoint);
return repos.Upload(objectToBeUploaded);
}
Source
是项目中可用的静态CancellationTokenSource
。
我还有一个我需要上传某个object
的端点列表。
Form
中的代码(它是使用WinForms
的非常小的项目)如下所示:
private async Task UploadObjectAsync(
string endpoint,
object objectToBeUploaded)
{
try
{
int elementId = await Task.Factory.StartNew(
() => Uploader.Upload(endpoint,objectToBeUploaded));
//do something with the returned value..
}
catch(OperationCanceledEception ex)
{
//handle the exception..
}
}
然后我像这样设置btnUpload.Click
处理程序,以便以后可以使用它:
this.btnUpload.Click += async (s, e) =>
{
foreach(var endpoint in endpoints)
{
await UploadObjectASsync(endpoint,someObject);
}
}
问题在于,无论何时我开始上传到所有端点(如何获取它们都无关紧要),我决定使用Source.Cancel();
取消上传过程,第一个UploadObjectAsync
将始终通过
Source.Token.ThrowIfCancellationRequested();
方法中的Upload
检查已通过。其余任务将被正常取消并妥善处理。
如何重新构建此代码,以确保第一个UploadObjectAsync
Task
也会被取消?
值得一提的是,我也无法访问上传过程本身的源代码(服务参考) - repos.Upload(objectToBeUploaded)
方法中的Upload
。
答案 0 :(得分:1)
你无能为力。 Upload方法不接受令牌。当您点击取消按钮时,第一个任务已经通过了取消检查。您可以向自己证明取消是一个时间问题,如果取消呼叫,则在投掷前增加10秒睡眠。然后所有任务都将取消。
答案 1 :(得分:1)
您需要使UploadRepository.Upload采用CancellationToken。
特别是当那是那个进行I / O操作的时候。那就是async/await
确实付出的代价。
这也有助于你摆脱它:Task.Factory.StartNew
,因为Upload
方法已经返回任务。没有必要分拆任务。
在您当前的设置中,如果有足够的时间启动任务(并通过ThrowIfCancellationRequested
),您将无法取消任何上传。即使需要30秒。
另外,您可能感兴趣:Task.Run
答案 2 :(得分:0)
问题是你无法阻止Upload
函数内发生的进程,除非它检查CancellationToken
任何终止本身的状态。
所以你可以做的是通过这样做来中止正在执行的线程:
int elementId = await Task.Factory.StartNew(() =>
{
try
{
using (Source.Token.Register(Thread.CurrentThread.Interrupt))
{
return Uploader.Upload(endpoint, objectToBeUploaded));
}
}
catch (ThreadInterruptedException ex)
{
throw new OperationCanceledEception(ex)
}
}, Source.Token);
使用Source.Token.Register(delegate)
函数可以在令牌被取消时使令牌调用该函数。这样,当前正在执行上传的线程就会立即抛出异常。
此方法仅在线程不时进入 WaitSleepJoin -State的情况下有效,因为只有在线程处于该状态时才会引发异常。请查看Thread.Interrupt
函数的文档。
另一种方法是使用Thread.Abort
和ThreadAbortedException
。这会在任何情况下终止你的线程,但它可能会破坏你的服务的内部状态,因为线程保持的锁定将无法正常释放。所以使用这种方法要非常小心。