0

我需要在单独的线程上创建一个 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
4

1 回答 1

1

您的问题是竞争条件。根据当前线程和线程池线程的调度方式,后面的行ThreadPool.QueueUserWorkItem可能有也可能没有正确的值。svc这很糟糕,我们不想这样做。

ThreadPool.QueueUserWorkItem是在线程池线程上运行东西的旧方式,然后忘记方式。您通常不想从那里同步回来(尽管您可以使用events,但是,这些都是阻塞方式)。

我们不想再阻塞应用程序线程了。所以,进来Async/AwaitTPL

这是你可以做到的方式:

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())
于 2013-07-23T21:00:59.860 回答