为什么 SyncLock 在这里不起作用?

Why is SyncLock not working here?

我正在开发一个 class 库,它将为 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 我正在使用它的方式,只是 "Static X as New Object" 在必须锁定的函数内创建同步对象。

是否因为回调实际上来自 .Net 框架之外的 win32 线程,所以 SyncLock 在这里不起作用?

我以前从未在VB中看到过static局部变量的用法。这样的事情存在对我来说是新闻。我建议您改用传统方式并使用 shared class 变量。

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
    Static OneAtATime As New Object

Static 关键字是 VB.NET 实施者脖子上的一个相当沉重的磨石。他们不得不支持它,因为它在以前的 Visual Basic 版本中经常使用,省略它会给想要更新其工具的程序员带来太多困难。

但它的遗留行为与线程非常不兼容,而线程是 .NET 中强烈支持的功能。以前不是问题,因为旧 VB 版本不支持创建线程。为该语句生成的 MSIL 代码量大量。你应该看看 ildasm.exe 实用程序。

它之所以庞大,是因为它需要做的事情。仅在第一次进入方法时初始化变量一次。不是很困难,它会自动生成另一个布尔变量来跟踪。但更困难的部分是为每个单独的线程执行一次。换句话说,它具有 [ThreadStatic] 行为。

这就是你要死的原因,每个线程都有自己的 SyncLock。这就是为什么您根本没有观察到同步 :) 您需要将其移出方法并声明它 Shared.