我正在努力将使用线程的旧代码替换为基于.NET 4.5 Task的系统。
我有以下要转换的子目录;
Public Function Delay(Milliseconds As Integer, ByRef Job As Job) As Boolean
For i As Integer = 1 To CInt(Milliseconds / 100)
Thread.Sleep(100)
If Job.IsCancelled Then Return True
Next
Return False
End Function
Job类是我自己的一个,但重要的是它包含一个整数,如果要取消该作业,则该整数设置为1。因此,Delay函数允许我将一个线程置于休眠状态X毫秒,但如果在此期间取消该作业,它将停止休眠并返回True。
我不知道怎么用Await Task.Delay做这个,这是我的尝试;
Public Async Function Delay(Milliseconds As Integer, Job As Job) As Tasks.Task(Of Boolean)
For i As Integer = 1 To CInt(Milliseconds / 100)
Await Tasks.Task.Delay(100)
If Job.IsCancelled Then Return True
Next
Return False
End Function
我遇到的问题是Async方法不允许我使用ByRef,这意味着它将无法检测作业何时被取消。另一个问题是await不能在try / catch / finally或synclock中使用。我的印象是你可以编写看起来像同步代码的异步代码。我该如何解决这些问题?
答案 0 :(得分:4)
您实际上并没有改变方法正文中的Job
变量,因此您根本不应该通过引用传递它,您应该按值传递它。
也就是说,除非Job
实际上是一个可变值类型而不是引用类型,在这种情况下 是你的问题,你应该通过不使用可变值类型来修复它这里。
还值得注意的是,如果您希望使用对象来封装异步操作的可能取消,则应使用CancellationToken
(以及随附的CancellationTokenSource
)。它将提供您需要的所有功能,特别注意,它将处理所有正确的同步,这样您就不会遇到从多个线程访问它的任何问题。它也恰好是一种参考类型。
如果您接受CancellationToken
,您也可以将其传递给Task.Delay
,允许在令牌取消时完成,而不是强制您的方法等到延迟已结束return false
。
答案 1 :(得分:1)
请务必将Job
声明为Class
,而不是Structure
。这将允许它传递ByVal
(默认值)并在您的代码中完美地工作,因为它将是一个参考类型,并且在您的方法中可以看到外部处理的突变。
由于您未在函数内部更改Job
,因此不应将其传递给ByRef
。