Monthly Archives: September 2004

Volatile reads and writes in VB

Warning: Seriously geeky stuff ahead. May not be suitable for children or anyone who doesn’t love the minutia of JIT optimizations and the CLR memory model.

A reader, Russ, asks:

Given the importance of volatile in light of Greg’s comments here: http://blogs.msdn.com/grantri/archive/2004/09/07/226355.aspx. why doesn’t vb.net support a similar construct? or are we not allowed to write high-performance multithreaded code using vb? :p

The construct that Russ is referring to is volatile fields. C# allows you to declare field with the “volatile” modifier, which results in all accesses to the field being prepended in the IL with the opcode “volatile.” I’d like to pretend that I could adequately explain to you what volatile reads and writes actually do, but there is a high probability that I would get it wrong because the CLR memory model is not my thing. It is, however, Vance’s thing and you can check out a message he wrote that talks in more detail about the subject.

Although VB doesn’t support the volatile modifier, you’re not up a creek without a paddle. In fact, as I said above, marking a field as volatile in C# doesn’t do anything to the field itself – it just makes sure that the compiler prefixes all reads and writes with the volatile modifier. Volatility is really a property of reading and writing from a field, not a property of the field itself. In fact, there may be situations where you only care at certain points whether you do a volatile read or write, in which case the volitile field modifier is overkill (because it makes all reads and writes volatile). A slightly more ideal situation would be able to mark just a particular read or write as being volatile.

The CLR provides a way to do this, sort of. The type System.Threading.Thread provides VolatileRead and VolatileWrite methods that allow you to do volatile reads and writes from fields without having to do any declarative work at all. So, everything is right with the world, correct? Unfortunately, no. If you look at the definition of VolatileRead and VolatileWrite, they use reference parameters (ByRef) to refer to the field that you’re reading or writing from. This is necessary because if they were regular value parameters (ByVal) the VolatileWrite wouldn’t work at all and VolatileRead wouldn’t give you the desired behavior. (That’s because value parameters are copied onto the stack. That copy wouldn’t be a volatile read. When you pass the address of the value, then the VolatileRead method can do a volatile read of the value at that address.)

The problem is that when you pass a variable to a reference parameter, the type of the variable must exactly match the type of the reference parameter. If it doesn’t, then you have to create a temporary variable of the right type, copy the value into the temporary, call the method and then copy the value out of the temporary. This isn’t an issue for primitive types because there are overloads of VolatileRead and VolatileWrite for all the primitive types. But what about some random reference type like an array (which occurs in Grant’s example)? The closest overload is a ByRef parameter of Object, but that’s still not going to be an exact match. That means you fall into the copy-in/copy-out scheme I talked about a moment ago, which screws everything up because the reads and writes to the temporary variable are not volatile! Arrrrg!

So, are VB users just screwed? Fortunately, no. There’s another method on System.Threading.Thread that can help out here: MemoryBarrier. When you call MemoryBarrier before a write or after a read, you effectively make the read or write a volitile read or write. (In fact, in Whidbey this is how VolatileRead and VolatileWrite are implemented.) You could even write a generic VolatileRead and VolatileWrite to do this for you in VB 2005:

Function VolatileRead(Of T)(ByRef Address As T) As T
VolatileRead = Address
Threading.Thread.MemoryBarrier()
End Function

Sub VolatileWrite(Of T)(ByRef Address As T, ByVal Value As T)
Threading.Thread.MemoryBarrier()
Address = Value
End Sub

So, yes, VB users are allowed to write high-performance multithreaded code… :)

It’s been quiet around here…

…because it’s been vacation season. On top of the trip to the beach I took a month or so ago, Andy and I just got back from a second vacation to Great Britian. A friend is moving to Oxford to work (and hang out with her boyfriend who lives there), so a few of us decided to take an impromptu trip to visit him along with her. We spent three or four days in London seeing the sights, then took the train up to Edinburgh for a few days and then ended up in Oxford for a few at the end of the trip. I’ve been to England before but not Scotland, so the trip was a lot of fun.

Anyway, now I’m back and not going anywhere for the foreseeable future. (Well, I am planning on going to the OOPSLA conference this year, but that’s up in Vancouver, BC which doesn’t count.) The pace should pick up somewhat as a result…

Recommended website: PInvoke.net

Matthias Benesch submitted a question asking if I had examples of how to use Win32 APIs in VB, specifically the API ReportFault. Searching on my site, I found that I’ve never actually mentioned the website http://pinvoke.net, which was an oversight. It’s a Wiki that the .NET community can use to trade Win32 API definitions for both VB and C#. I recommend checking it out when you have questions like this and, if you’re lucky, it’ll have an answer. (I also recommend submitting API definitions to it as well. Help out the community!) Unfortunately, it doesn’t seem to have a definition for ReportFault yet (and I don’t have one handy), so it doesn’t address Matthias’s question. Maybe someone will see this and submit it there in VB…