我正在开发一个类库,它将为CLR应用程序提供异步通信。
SslStream上有异步读取(BeginRead),其中一个回调例程由多个流共享。 我不希望在调试期间并行处理回调,因此我创建了一个关键部分:
Private Sub Callback_Read(ByVal ar As IAsyncResult)
Static OneAtATime As New Object
SyncLock OneAtATime
Dim ThisSslStream As SslStream = DirectCast(ar.AsyncState, SslStream)
...
End SyncLock
End Sub
令我惊讶的是,这并不起作用,至少在我在SyncLock块中设置断点时是这样。多个流的回调同时在其中运行,无需在入口点等待,直到前一个线程离开它为止。
单步执行是一场噩梦,特别是当流同时关闭(关闭)时:执行流1的行,执行流2的行,执行下一行1,执行下一行2,依此类推,通过整个街区。
我想也许你需要的东西不仅仅是一个通用的" New Object",但后来我看到堆栈溢出中至少有一个答案说明SyncLock正是我使用它的方式,只是"静态X作为新对象"在必须锁定的函数中创建同步对象。
是不是因为回调实际上来自.Net框架之外的一个win32线程,SyncLock在这里不起作用?
答案 0 :(得分:8)
Static OneAtATime As New Object
Static关键字是VB.NET实现者的一个相当重要的磨刀石。他们有支持它,因为它在以前的Visual Basic版本中经常使用,省略它会给想要更新其工具的程序员带来太多困难。
但它的遗留行为与线程非常不兼容,线程在.NET中得到了非常强烈的支持。之前不是问题,因为旧的VB版本不支持创建线程。为该语句生成的MSIL代码量是大量。您应该看看ildasm.exe实用程序。
由于它需要做的事情,这是巨大的。这是第一次输入方法时仅初始化变量一次。不是非常困难,它会自动生成另一个保持跟踪的布尔变量。但更难的部分是为每个单独的线程做一次。换句话说,它具有[ThreadStatic]行为。
这就是杀死你的原因,每个线程都有自己的SyncLock。这就是为什么你没有观察到同步的原因:)你需要将它移出方法并声明它Shared
。
答案 1 :(得分:2)
我之前从未见过在VB中使用static
局部变量。存在这样的事情对我来说是新闻。我建议你以传统的方式改为使用shared
类变量。
public Class Test
Private shared SyncRoot As Object = new Object()
Private Sub Callback_Read(ByVal ar As IAsyncResult)
SyncLock SyncRoot
Dim ThisSslStream As SslStream = DirectCast(ar.AsyncState, SslStream)
...
End SyncRoot
End Sub
End Class