Henry
Henry

Reputation: 3013

Trying to understand how SyncLock Works

I made a two static classes

NotInheritable Class gObject2
    Public Shared TestSyncLock As String = "test"
End Class

NotInheritable Class gObject3
    Public Shared TestSyncLock As String = "test"
End Class

Then I have two aspx

Synclock1.aspx:

Public Class SyncLock1
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        SyncLock gObject2.TestSyncLock
            Thread.Sleep(10000)
        End SyncLock
    End Sub

End Class

Synclock2.aspx

Public Class SyncLock2
    Inherits System.Web.UI.Page
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        SyncLock gObject3.TestSyncLock
            SomeDiv.InnerHtml = "It works"
        End SyncLock
    End Sub
End Class
  1. When I go to synclock1.aspx it spins for 10 seconds and shows a blank page as expected.
  2. When I go to synclock2.aspx it spits out it works

Everything is good so far.

Now when I go to synclock1.apx and then in another browser got to synclock2.aspx, synclock2.aspx doesn't finish loading until synclock1.aspx finishes.

These are 2 different objects I'm locking with synclock, but it treats them the same. Why is this?

Upvotes: 1

Views: 570

Answers (1)

TnTinMn
TnTinMn

Reputation: 11801

The SyncLockstatement takes an object reference as its argument. As the String type is a reference type, your code is satisfying that constraint. However, due to String Interning in .Net, the literal value equality of the two separate String references is also causing referential equality between gObject2.TestSyncLock and gObject3.TestSyncLock.

From: String.IsInterned Method - Remarks (emphasis added)

The common language runtime automatically maintains a table, called the intern pool, which contains a single instance of each unique literal string constant declared in a program, as well as any unique instance of String you add programmatically by calling the Intern method.

The intern pool conserves string storage. If you assign a literal string constant to several variables, each variable is set to reference the same constant in the intern pool instead of referencing several different instances of String that have identical values.

Since both gObject2.TestSyncLock and gObject3.TestSyncLock are pointing to the same String reference, SyncLock gObject2.TestSyncLock will block SyncLock gObject3.TestSyncLock.

The subject code is a good example of how string interning can cause unexpected behavior. The article Interning Strings and immutability provides additional details on the mechanics of interning and also provides another example where interning can cause unexpected results.

So the moral of this story is to avoid using strings as the argument for SyncLock. It is safer to use something like the following:

NotInheritable Class gObject2
     Public Shared TestSyncLock As New Object
End Class

NotInheritable Class gObject3
     Public Shared TestSyncLock As New Object
End Class

Upvotes: 3

Related Questions