Collaboration: At the Extremities of Extreme
Jason Ayers share the observations he made watching a team of developers collaborating in real time on the same code base, pushing XP, pair programming and continuous integration to their extremes.
The content has been bookmarked!
There was an error bookmarking this content! Please retry.
Posted by Jonathan Allen on Jan 23, 2010
The ConcurrentDictionary is a cornerstone in .NET 4.0’s greatly increased emphasis on parallel and concurrent programming. But before we delve into it, we offer a review of the problems in previous versions of .NET.
The first version of the hash table in .NET was System.Collections.Hashtable. While it wasn’t thread-safe, you could in theory get a thread-safe wrapper simply by calling Hashtable.Synchronized. Unfortunately this wrapper wasn’t actually thread-safe because of the way it was used.
Say, for example, you wanted to check if a key exists in the collection. If not, then you want to perform a non-repeatable operation, the result of which would be stored there. Even though both ContainsKey and set_Item are independently thread-safe, there is no way to directly compose them. Instead you have to take a lock on the SyncRoot, negating the whole reason you asked for a synchronized version in the first place.
When .NET 2.0 introduced generics and System.Collections.Generic.Dictionary, Microsoft punted the issue. Developers had to take explicit locks on their own or just
.NET 3.5 didn’t add anything techniques, but it did make them a whole lot easier to implement with the increased emphasis on functional programming. First of all, the idea of defining custom delegates disappeared. From that point on any well designed API would be expected to reuse the generic Action and Func delegates. Another benefit was the introduction of lambda notation to VB and a greatly improved notation in C#. As a result, developers could easily create their own synchronized wrappers with APIs such as this:
public TValue GetOrAdd(TKey key, Func<TKey, TValue> valueFactory)
Unlike the earlier versions where developers had to muck about with locks, this method on the new ConcurrentDictionary looks like it hard to use incorrectly. Simply provide a key and a delegate that will be executed if the key doesn’t exist. A long as the function itself is thread-safe, everything should be atomic.
Well, no. To “avoid the myriad of problems that can arise from executing unknown code under a lock”, the valueFactory delegate isn’t executed under the locks. So there is the possibility of a race condition and developers need to ensure that the valueFactory delegate only performs repeatable operations.
If you need this functionality, you have to combine the ConcurrentDictionary class with the Lazy class. An example of this is included in the AsyncCache class, which is being shipped as a sample.
While subject to change, currently the ConcurrentDictionary class is implemented with lock-free reads. To improve performance, developers can provide an estimated number of writer threads. This will govern how many fine-grained locks the hash table uses.
You can learn more about the ConcurrentDictionary from Stephen Toub’s post.
Improve Java Garbage Collection, Runtime Execution, and JVM visibility with Zing
Using Drools? See what you're missing! Get the Power of Drools with the Assurance of Red Hat
Monitor your Production Java App - includes JMX! Low Overhead - Free download
Why NoSQL? A primer on Managing the Transition from RDBMS to NoSQL
In the 4th paragraph, it seems not ends normally,
"Developers had to take explicit locks on their own or just...",just what?
I think it was meant to say: "As long as the function..." instead of "A long as the function...".
Thanks for the article thought.
When I read stuff like this, I have to ask myself, is it time to start learning a language that was written to handle concurrency from day one? Things like this really feel shoehorned in.
Jason Ayers share the observations he made watching a team of developers collaborating in real time on the same code base, pushing XP, pair programming and continuous integration to their extremes.
Michael Snoyman presents Yesod, a web framework written in Haskell and containing a web server, templating, ORM, libraries (templating, gravatar, etc.).
Richard Kreuter and Kyle Banker on how to avoid classical RDBMS transactional systems by using compensation mechanisms, transactional messaging or transactional procedures.
Attila Szegedi talks about performance tuning Java and Scala programs at Twitter: how to approach GC problems, the importance of asynchronous I/O, when to use MySQL/Cassandra/Redis, and much more.
One category of risk that project teams need to ensure they address is business value failure – delivering a product that fails to provide value for the business investor.
InfoQ spoke to the authors of Software Systems Architecture on a couple of new topics, the System Context viewpoint and Agile, which have been added to the second edition.
Alex Papadimoulis discusses ugly code, where it comes from, how to avoid it, and how to get rid of it.
John Davies examines Visa’s architecture and shows how enterprises have architected complex integrations incorporating Hadoop, memcached, Ruby on Rails, and others to deliver innovative solutions.
3 comments
Watch Thread Reply