Locking a member Variable in Memory
Variable life time is normally not a problem in VB but but I'm working in the context of a webservice and variable persistence is quite different.
In a normal VB program Member variables are the variables common to all routines.... and not declared in a function or subroutine.
They are assumed to have a lifetime for the lifetime of the program.
In a normal program I can do this:
Class
Member variable
Subroutine A
Subroutine B
end class
The member variable has a lifetime of the program. Static is not a legal option for a member variable.
The environment in a webservice appears to be quite different.
The architecture of my webservice is similar to the above with two webmethods.
Class
Member variable (dictionary database)
Webmethod A (Asynch database loader)
Webmethod B (database processing - driven by Client-side Java)
end class
I load the database in A and return in B to find the database empty as it is not being persisted across calls.
Question: How do I lock the dictionary in memory so that it is persisted

Locking a member Variable in Memory
prayag
Goodness this is going to be embarassing because my partner has been beating me over the head about C#. I originally come from Digital. All of our languages were case insensitive and had no brackets. I will never really like C or feel comfortable with it which is probably why I settled into basic.
All of the data is the same. It will never change.
Thank you all.
StephenJr
1.) I am sure and have been sure why the data is persisting. I do understand the instantiation and the classes. That is not a problem at all. I fully understand the theory behind this.
What I do not understand, is why it was this was so simple when nomally using a shared variable such as cursor.position is like pulling teeth to use or expose.
2.)
I had already put locking in as a synch technique. Before I read this.
Dim BinFormatter As New BinaryFormatter() Dim obj As Object Dim HouseDBLock As New Object
SyncLock HouseDBLock Try CType(obj, Dictionary(Of Integer, List(Of String)))) Catch e As SystemException
ReadDatabase =
False End Try End SyncLockBinFormatter =
Nothingfsi.close ' Thank you.
obj =
NothingHouseDBLock =
Nothing End FunctionWhat I used to do in VMS was disk cluster diskshadowing. mainframe synchronization during cluster transistions.
3.) Thank you for that. Using didn't lend itself well to this. Perhaps after the code is stabilized.....
tech710
If the data is common to all users, a shared (static in C#) property is the best approach. If the data is scoped per user, then persistance via session state is probably the best way to go.
hansifer
1. If you are not sure why the class is persisting the database between calls, then you need to read up on shared members within classes.
Marking a member 'shared' causes the member to be shared among all instances of your class. So in your situation, HouseDb is shared, therefore there will only be one instance of it no matter how many times an instance of your WebService gets created (which occurs everytime a method is called on it across the web).
If shared was removed from the declaration of HouseDb, then LoadDb would load the database everytime an instance of the WebService was created (which as I stated before, occurs everytime a method is called on it across the web). Once a method call has finished, the WebService instance goes out of scope, therefore so does the HouseDb member.
You need to be aware of what shared is doing. Basically it means that every single method call on the WebService and every single user that calls the WebService will be seeing the exact same instance of HouseDb.
2. You need to make LoadDb thread-safe. Currently because HouseDb is marked shared, it can mean that multiple threads can access it at the same time.
This can mean that it possible for ReadDatabase() to be called multiple times. Read up on the SyncLock() construct.
3. Your ReadDatabase method in the DB class is leaking resources. FileStream is a wrapper around an unmanaged resource and needs to be closed. Setting local variables to Nothing in .NET does absolutely nothing. You instead need to call FileStream.Close().
VB 2005 has a new construct called Using that makes it easy to do this properly:
Using fsi New System.IO.FileStream("H:\VirtualRealty\App_data\DwellingFeatures.dbs", FileMode.Open, FileAccess.Read)
End Using
Ernst Kuschke
I'm used to writing mainframe drivers in kernel mode at IPL8 in assembler. I promise I know how to write thread safe code.
I will not use shared variables because of their lack of flexibility.
I cringe everytime I use cursor.position. Almost invarairably I have to write a function that looks like this:
Private Shared Function Curpos () As Point
return cursor.position
End function.
There are times that I've called the API because I find cursor.position so inconvenient.
I love vs2005. It's a fine project but if there is one unusable feature it's shared variables and the thread safe restrictions.
I think I've only declared one in my life and would far prefer do this synchronously rather than to declare a shared variable. I don't think there is any more irritating in the entire VB world.
I'm sorry to complain, but shared variables just aren't something that I'll use. I really wish there was a mode if vs2005 that would turn thread safety off.
This dictionary is the heart and soul of this and it is referenced constantly. The irony here is that this dictionary is read-only, no-one ever writes to it after it is de-serialized. It will have 866 records with 566 variables each and the data will remain unchanged forever.
Marc Miller
I meant that a shared property in Visual Basic (which is called a static property in C#) is the way to go. Not that C# is the way to go.
meedietoo
It may be less than relavant because this works....
I don't think it should work but it works and I don't know why.
Public
Shared HouseDb As Dictionary(Of Integer, List(Of String))<WebMethod(enablesession:=
True, cacheduration:=300)> _ Public Sub LoadDB() ' Database Preload If HouseDb Is Nothing Then Dim database As New DBdatabase.ReadDatabase(HouseDb)
End If End Sub<WebMethod()> _
Public Function RetsDBQuery(ByVal HomeType As String, ByVal Locale As String, ByVal LowValue As String, _ ByVal HighValue As String, ByVal LowBedrooms As String, ByVal HighBedrooms As String) As String If HouseDb Is Nothing Then Dim database As New DBdatabase.ReadDatabase(HouseDb)
End If If HouseDb.Count <> 0 Then Dim sHomeType As String = Server.HtmlEncode(HomeType) Dim sLocale As String = Server.HtmlEncode(Locale) Dim sLowValue As String = Server.HtmlEncode(LowValue) Dim sHighValue As String = Server.HtmlEncode(HighValue) Dim sLowBedrooms As String = Server.HtmlEncode(LowBedrooms) Dim sHighBedrooms As String = Server.HtmlEncode(HighBedrooms) Return Inquiry(sLowValue, sHighValue, sHomeType, sLowBedrooms, sHighBedrooms, sLocale) Else Return "Database failed to load" & CurDir() End If End Function<Serializable()>
Public Class DB ' DBLOADER Public Sub New() 'ByRef Dic As Dictionary(Of Integer, ArrayList)) End Sub Public Sub ReadDatabase(ByRef HouseDb As Dictionary(Of Integer, List(Of String))) Dim fsi As System.IO.FileStream = Nothing If CurDir() = "I:\Visual Studio 8\Common7\IDE" Then ' Debug mode New System.IO.FileStream("H:\VirtualRealty\App_data\DwellingFeatures.dbs", IO.FileMode.Open, FileAccess.Read) ' Open the dictionary in the defaulting directory Else New System.IO.FileStream("\App_data\DwellingFeatures.dbs", IO.FileMode.Open) ' Open the dictionary in the defaulting directory End If Dim BinFormatter As New BinaryFormatter() Dim obj As Object Try CType(obj, Dictionary(Of Integer, List(Of String)))) Catch e As SystemException End TryBinFormatter =
Nothingobj =
Nothingfsi =
Nothing End SubEnd
ClassIt works exactly as I need and want it to. That's great but I'm very puzzled. I've also put break points in the RetsDBQuery and the break point never goes off where the database is nothing. And there is data in the database.
It really shouldn't be behaving this way... meaning working. Btw there is a lot more code in the service. This is the I/O engine so to speak and that what we are addressing.
Dorkboy
Yeah I know and there's nothing I hate worse than shared variables. I avoid them like the plague.
They are really restrictive in their use, No Because of thread safety
JBinGA
Kinjal Patel
AvalonJulie
In the past, every time I've tried to use a shared variable I get those green squiggles that says "this expression will not be evaluated."
What a shared variable does is NO mystery at all.
On the synclock. You mean it's a lock that is only Process or instantiation wide
That was an error on my part. I'm used to system wide mutexes etc, not something with a granularity that narrow.
David Snipp
1. I am confused as to why using a shared member is so hard. If anything it is easier because you don't need an instance of the object to access.
2. The locking you have implemented won't actually work because:
1. You are locking a new instance of an object each time. So if another thread enters this method, then both threads are locking a different object.
2. You have placed the lock around the wrong bit of code
Here is some code showing what it should look like (I haven't compiled this):
Private Shared LockObject As New Object
Public Shared HouseDb As Dictionary(Of Integer, List(Of String))
Public Shared Sub LoadDB()
If HouseDb Is Nothing Then
SyncLock(LockObject)
If HouseDb Is Nothing Then
HouseDb = ReadDatabase()
End If
End SyncLock
End If
End Sub
Public Function ReadDatabase() As Dictionary(Of Integer, List(Of String))
// Read database and return it
End Function
As I said before, you also don't need to set your local variables to Nothing. It does absolutely nothing.
3. Using also has the benefit of ensuring that your filestream is closed even in the case of an exception.