我需要在单独的线程上创建WCF ChannelFactory。我现在面临的问题是变量svc
并不总是返回一个值:
...
Dim svc As T = Nothing
Dim svcft As New DuplexChannelFactory(Of T)(caller, ep)
ThreadPool.QueueUserWorkItem(New WaitCallback(Sub(obj) svc = svcft.CreateChannel()))
...
大多数情况下svc
将返回一个空值,但有时会返回一个好的引用。我做错了什么?
我根据YK1的评论修改了我的代码。它仍然没有解决问题 - svc仍然没有设置:
Task.Factory.StartNew(
Sub()
svc = svcft.CreateChannel()
End Sub
).ContinueWith(
Sub()
svcft = Nothing
End Sub
)
If svc Is Nothing Then
Throw New Exception("Creating service reference failed.") '<== get the error here...
End If
答案 0 :(得分:1)
你的问题是竞争条件。 ThreadPool.QueueUserWorkItem
之后的行可能会或可能不具有svc
的正确值,具体取决于当前线程和线程池线程的调度方式。这很糟糕,我们不想这样做。
ThreadPool.QueueUserWorkItem
是以火和忘记的方式在线程池线程上运行东西的旧方法。您通常不希望从那里同步(尽管您可以使用events
,但这些都是阻止方式)。
我们不想再阻止应用程序线程了。因此,请Async/Await
和TPL
。
以下是您可以这样做的方式:
Async Function MyFuncAsync(Of T)() As Task
...
Dim svc As T = Nothing
Dim svcft As New DuplexChannelFactory(Of T)(caller, ep)
svc = Await Task.Run(Funtion() svcft.CreateChannel())
...
End Function
如果您不使用.NET 4.5并且不想使用async/await
,则可以直接使用TPL
API。
...
Dim svc As T = Nothing
Dim svcft As New DuplexChannelFactory(Of T)(caller, ep)
Task.Factory.StartNew(
Sub()
svc = svcft.CreateChannel()
End Sub
).ContinueWith(
Sub(t)
`rest of code here
End Sub
)
如果你的主线程是UI线程(WPF / Winforms),如果你想在UI线程上同步,那么你可以继续在UI线程上运行。 (async/await
自动捕获syncdhronizationcontext
以上。
...
Dim svc As T = Nothing
Dim svcft As New DuplexChannelFactory(Of T)(caller, ep)
Task.Factory.StartNew(
Sub()
svc = svcft.CreateChannel()
End Sub
).ContinueWith(
Sub(t)
`rest of code here
End Sub,
TaskScheduler.FromCurrentSynchronizationContext())