Should I always lock static methods? - vb.net

In the following example GetList returns an instance of a static (shared) variable. That one needs locking in order to be thread-safe.
But what about DoSomething which doesn't use any static variables outside the method? Does it need locking too?
EDIT: I'd like to clarify that in this particular case I expect DoSomething to always print 0-100 in sequence (i.e. no 0123745...) regardless of number of calling threads. Or, in general, that different threads don't affect each other's variables (printing to console is only an example). The language in the following example is VB.NET.
As paxdiablo said:
In this case, it appears the only thing touched is the local variable
i which would have a separate copy for every function invocation.
In other words, it wouldn't need protecting.
That is exactly what I was trying to solve. Thank you!
Public Class TestClass
Private Shared lock As New Object
Private Shared list As List(Of Integer)
Public Shared Function GetList() As List(Of Integer)
SyncLock lock
If list Is Nothing Then
list = New List(Of Integer)
End If
Return list
End SyncLock
End Function
Public Shared Sub DoSomething()
Dim i As Integer
For i = 0 To 100
Console.WriteLine(i.ToString)
Next
End Sub
End Class

Well, that would mostly depend on the language which you haven't specified but, generally, if code doesn't touch a resource that another thread can also touch, it doesn't have to be protected.
In this case, it appears the only thing touched is the local variable i which would have a separate copy for every function invocation. In other words, it wouldn't need protecting.
Of course, it could be argued that the console is also a resource and may need protection if, for example, you didn't want lines interfering with each other (synclock the write) or wanted the entire hundred lines output as a single unit (synclock the entire for loop).
But that won't really protect the console, just the block of code here that uses it. Other threads will still be able to write to the console by not using this method.
Bottom line, I don't think you need a synclock in the second method.
This section below is not relevant if you're using SyncLock in VB.Net (as now seems to be the case). The language guarantees that the lock is released no matter how you leave the block. I'll leave it in for hysterical purposes.
I'd be a little concerned about your synclock placement in the first method, especially if the return statement was a transfer of control back to the caller (and the synclock didn't automatically unlock on scope change). This looks like you can return without unlocking, which would be a disaster. I would think the following would be more suitable:
Public Shared Function GetList() As List(Of Integer)
SyncLock lock
If list Is Nothing Then
list = New List(Of Integer)
End If
End SyncLock
Return list
End Function

In general, no.
You need to be clear on the reason why GetList has the locking applied. It's not, as you imply in your first sentence, because it's returning a static variable. You could remove the locking code, and GetList would still be thread safe. But, with the locking, there's an additional guarantee - that the list will only be created once, and all callers of this code will receive a reference to the same list.

Why not avoid the lock altogether and just do this:
Public Class TestClass
Private Shared lock As New Object
Private Shared list As New List(Of Integer)
Public Shared Function GetList() As List(Of Integer)
Return list
End Function
Public Shared Sub DoSomething()
Dim i As Integer
For i = 0 To 100
Console.WriteLine(i.ToString)
Next
End Sub
End Class

Related

Is double synclock within the same thread ok?

I have a situation where multiple threads may access a class, the class consists of 3 private values and 6 properties that get/set various arithmetic combinations of the 3 values. Then I have 6 more properties that are just type conversions as they call on the first 6 properties as a part of their get/set operation.
All the get/set functions of the first 6 properties are synclocked to the same object. I wanted to synclock the get/set functions of the other 6 too to the same object since they use some of the same utility objects but it occurred to me that this will lead to synclocking the same object twice in a row.. sorta like this:
Private lock As New Object
Private _dCool As Double
Public Property dCool As Double
Get
SyncLock lock
Return _dCool
End SyncLock
End Get
Set(value As Double)
SyncLock lock
_dCool = value
End SyncLock
End Set
End Property
Public Property iCool As Integer
Get
SyncLock lock
Return dCool
End SyncLock
End Get
Set(value As Integer)
SyncLock lock
dCool = value
End SyncLock
End Set
End Property
There is no need to synclock iCool in this example but its just to illustrate the problem. As far as I've tested, there seem to be no problems with this but just wanted to ask if some problems i cant see right now could come up by doing this?
Yes, not a problem. The VB.NET compiler generates calls to Monitor.Enter/Exit() when you use the SyncLock keyword, along with Try/Finally blocks to ensure that the entered monitor is always exited. The MSDN article for Monitor.Enter says:
It is legal for the same thread to invoke Enter more than once without it blocking; however, an equal number of Exit calls must be invoked before other threads waiting on the object will unblock.
Relevant phrase bolded. The Finally block ensure that the Exit() call requirement is always met.

Is there a way to determine the value of a property on a form that calls a method in a seperate class library

Specifically aimed at winforms development.
I suspect that the answer to this is probably No but S.O. has a nice way of introducing me to things I didn't know so I thought that I would ask anyway.
I have a class library with a number of defined methods therein. I know from personal experimentation that it is possible to get information about the application within which the class library is referenced. What I would like to know is whether it would be possible to get information about the value of a property of a control on a form when a routine on that form calls a method in my class library without passing a specific reference to that form as a parameter of the method in the class library?
So purely as an example (because it's the only thing I can think of off the top of my head). Is there a way that a message box (if it had been so designed to do so in the first place) could 'know' from which form a call to it had been made without that form being specifically referenced as a parameter of the message box in the first place?
Thanks for any insights you might have.
To address the example of the MessageBox, in many of the cases you can use the active form. You can retrieve it by using Form.ActiveForm. Of course, as regards the properties that you can request, you are limited to the properties provided by the Form or an interface that the Form implements and that the method in the other assembly also knows. To access other properties you can use Reflection, but this approach would neither be straightforward nor would it be clean.
In a more general scenario, you could provide the property value to the method as a parameter. If it is to complex to retrieve the value of the property and the value is not needed every time, you can provide a Func(Of TRESULT) to the method that retrieves the value like this (sample for an integer property):
Public Sub DoSomethingWithAPropertyValue(propValFunc As Func(Of Integer))
' Do something before
If propertyValueIsNeeded Then
Dim propVal = propValFunc()
End If
' Do something afterwards
End Sub
You call the method like this:
Public Sub SubInForm()
Dim x As New ClassInOtherAssembly()
x.DoSomethingWithAPropertyValue(Function() Me.IntegerProperty)
End Sub
I kind of question your intentions. There's no problem sending the information to a function or the constructor.
Instead of giving the information to the class, the class would ask for the information instead using an event.
Module Module1
Sub Main()
Dim t As New Test
AddHandler t.GetValue, AddressOf GetValue
t.ShowValue()
Console.ReadLine()
End Sub
Public Sub GetValue(ByRef retVal As Integer)
retVal = 123
End Sub
End Module
Class Test
Public Delegate Sub DelegateGetValue(ByRef retVal As Integer)
Public Event GetValue As DelegateGetValue
Public Sub ShowValue()
Dim val As Integer
RaiseEvent GetValue(val)
Console.WriteLine(val)
End Sub
End Class

Adding field in custom deserialization constructor

I have one class implementing ISerializable interface, with one private field that is saved and retrieved:
Protected Sub New(ByVal info As SerializationInfo, ByVal context As StreamingContext)
_name= info.GetString("_name")
End Sub
Now, I want to add a new private field, but since it did not exist previously, when I try to open a serialized object I get an exception when trying to get this field, in the custom deserialization constructor. The solution I've come up with is to use a Try...Catch block, as follows:
Protected Sub New(ByVal info As SerializationInfo, _
ByVal context As StreamingContext)
_name= info.GetString("_name")
Try
_active= info.GetBoolean("_active")
Catch ex As Exception
_active= False
End Try
End Sub
It works, but it seems a bit messy to me, moreover because I will have to add a new Try...Catch block for each new field I want to add.
Is there any better way of doing this?
Thanks!
EDIT:
In this answer t0mm13b says that "There is a more neater way to do this in 2.0+ upwards". Any ideas about what is he talking about?
There is no built-in method that allows you to first determine if a particular value exists (e.g. Exists). There is also no Get... method which simply returns Nothing if the value does not exist (e.g. TryGet). However, the one way that you can do it which avoids the potential for exceptions is to use a For Each loop to iterate through all of the values in the SerializationInfo collection. For instance:
For Each i As SerializationEntry In info
Select Case i.Name
Case "_name"
_name = DirectCast(i.Value, String)
' ...
End Select
Next
Note: It may be surprising to you that you can use a For Each loop on a SerializationInfo object, since it does not implement the IEnumerable interface (nor the generic equivalent). However, For Each in VB.NET actually works with any object that has a public GetEnumerator method. So, even though it leads to some confusion, objects don't technically need to implement IEnumerable in order for you to iterate through them with a For Each loop. Since the SerializationInfo class does expose a public GetEnumerator method, you can iterate through it with a For Each loop.

What should I SyncLock in this code, and where?

I have a class that has two method in it, one calls a class which creates and executes a number of threads, the other is an event handler that handles an event raised when those threads complete (and then calls the first method again).
I understand that the method that handles the event runs in the thread that raised the event. So as such, I SyncLock a member variable that says how many threads are running and subtract one from it:
SyncLock Me ' GetType(me)
_availableThreads -= 1
End SyncLock
So I have a few questions:
Main Question: Should I be SyncLock'ing _availableThreads everywhere in the class - i.e in the method that creates the threads (which adds 1 when a thread is created)
Side Questions related to this question:
I'd usually SyncLock the current instance, but I've seen code that SyncLocks the type instead, so what is the difference between sync locking Me (Current Instance) and GetType(Me)?
Would there be a performance difference between the two? and is there anything smaller I'd be able to lock for the above that doesn't affect anything else - perhaps a separate 'padlock' object created for the sole purpose of locking things within a class?
Note: The sole purpose of _availableThreads is to control how many threads can run at any given time and the threads process jobs that can take hours to run.
Code:
Public Class QManager
Private _maxThreadCount, _availableThreads As Integer
Public Sub New(ByVal maxThreadCount As Integer)
Me.MaximumThreadCount = maxThreadCount
End Sub
Public Sub WorkThroughQueue()
//get jobs from queue (priorities change, so call this every time)
Dim jobQ As Queue(Of QdJobInfo) = QueueDAO.GetJobList
//loop job queue while there are jobs and we have threads available
While jobQ.Count > 0 And _availableThreads <= _maxThreadCount
//create threads for each queued job
Dim queuedJob As New QdJob(jobQ.Dequeue)
AddHandler queuedJob.ThreadComplete, AddressOf QueuedJob_ThreadCompleted
_availableThreads += 1 //use a thread up (do we need a sync lock here?)***************************
queuedJob.Process() //go process the job
End While
//when we get here, don't do anything else - when a job completes it will call this method again
End Sub
Private Sub QueuedJob_ThreadCompleted(ByVal sender As QdJobInfo, ByVal args As EventArgs)
SyncLock Me //GetType(me)
_availableThreads -= 1
End SyncLock
//regardless of how the job ended, we want to carry on going through the rest of the jobs
WorkThroughQueue()
End Sub
#Region "Properties"
Public Property MaximumThreadCount() As Integer
Get
Return _maxThreadCount
End Get
Set(ByVal value As Integer)
If value > Environment.ProcessorCount * 2 Then
_maxThreadCount = value
Else
value = Environment.ProcessorCount
End If
LogFacade.LogInfo(_logger, "Maximum Thread Count set to " & _maxThreadCount)
End Set
End Property
#End Region
End Class
You shouldn't SyncLock the instance or the type. You always want to SyncLock on a variable that is fully within the control of the class, and neither of those are. You should declare a private New Object and use that for your SyncLock.
Private lockObject as New Object()
...
SyncLock lockObject
...
End SyncLock
Unfortunately, you need to do a few things differently here.
First off, I'd recommend avoiding SyncLock, and using Interlocked.Increment and Interlocked.Decrement to handle changing _availableThreads. This will provide thread safety for that variable without a lock.
That being said, you still will need a SyncLock around every access to your Queue - if it's being used from multiple threads. An alternative, if you're using .NET 4, would be to change over to using the new ConcurrentQueue(Of T) class instead of Queue. If you use SyncLock, you should create a private object only accessible by your class, and use it for all synchronization.
You should be using the Interlocked class here, the Decrement() method to decrease the count. Yes, everywhere the variable is accessed.
Using SyncLock Me is as bad as SyncLock GetType(Me). You should always use a private object to lock on so nobody can accidentally cause a deadlock. The golden rule is that you cannot lock data, you can only block code from accessing data. Since the code is your private implementation detail, the object that holds the lock state must also be a private detail. Neither your object (Me) nor the Type of that object is private. Allowing other code to lock it by accident.
You can substitute the thread counter with Semaphore. If you use Semaphore you do not need to exit from while loop and neither it is necessary to call WorkThroughQueue() from ThreadCompleted event handler. Semaphore is thread safe so you can use it without locking.
http://www.albahari.com/threading/part2.aspx#_Semaphore

Shared method in VB.NET cannot handle this why?

(I tried with this question but this code isolates the problem better.)
I have this code:
Public Shared Sub PopulateTextFields(ByRef stuffList As List(Of Stuff))
Dim aStuff As New Stuff
For Each aStuff In stuffList
DoStuff(aStuff)
Next
End Sub
Private Sub DoStuff(ByRef theStuff as Stuff)
....
End Sub
I get the following error highlighting DoStuff(aStuff):
Cannot refer to an instance member of
a class from within a shared method or
shared member initializer without an
explicit instance of the class.
Didn't I get an explicit instance of Stuff when I wrote the Dim statement?
Don't understand what's wrong. Thanks in advance!
I think the problem lies with the Subroutine DoStuff. If both your subs lie in the same class, you are trying to refer to DoStuff from within PopulateTextFields, which is a shared sub.
In order to achieve this, you need to declare DoStuff as Shared as well.
Yes you did, but you aren't referencing aStuff you are trying to call it on the static implementation of the class, furthermore you are resetting aStuff to a separate instance through each loop iteration.. change your code to:
Public Shared Sub PopulateTextFields(ByRef stuffList As List(Of Stuff))
Dim aStuff As New Stuff
For Each aStuff In stuffList
aStuff.DoStuff(aStuff)
Next
End Sub
Private Sub DoStuff(ByRef theStuff as Stuff)
....
End Sub
And it should work, but maybe not as expected, I don't really know your intent of having a private member that handles changing a separate reference of it's own type.
It may be appropriate to change the signature of DoStuff to:
Private Sub DoStuff()
....
'Use the Me reference here to change myself
....
End Sub
and then call it as:
aStuff.DoStuff() 'Will modify this instance
You didn't share which type these methods belong to. From your confusion, I'm guessing it's part of the "Stuff" class. But it doesn't really matter. It sounds like you're forgetting one of two things:
Creating an instance of the type in the shared method doesn't somehow attach the shared method to that instance. You could create 10 or 1000 instances in the method, after all.
Passing an instance as a parameter doesn't associate the function with an instance. A parameter is not a call site.
Either way, it comes down to providing an instanced call site. Your DoStuff function is not shared, and so the compiler thinks it needs access to state provided by a specific instance of your type. That instance is the method's call site. You either need an instance of the type to call it from: SomeInstance.DoStuff(aStuff) , or if the method doesn't really need access to any type state you need to mark it shared and call it like this: Stuff.DoStuff(aStuff)