为什么SyncLock不能在这里工作?

时间:2015-03-26 13:55:46

标签: vb.net asynccallback synclock

我正在开发一个类库,它将为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在这里不起作用?

2 个答案:

答案 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