- Table of Contents
- .NET Book Recommendations
- What Is .NET?
- The Microsoft .NET Framework
- The Common Language Runtime (CLR), the Common Type System (CTS), and the Common Language Specification (CLS)
- .NET Framework Class Library
- Visual Studio .NET
- .NET Enterprise Servers and .NET My Services
- .NET Compliant Languages
- C#
- Visual Basic .NET (VB .NET)
- ASP.NET
- XML Web Services
- ADO.NET
- XML.NET
- Windows Forms
- Why .NET?
- Displaying Errors with the Error Provider
- COM Interoperability
- Comparing Java and .NET
- Calling Unmanaged Code
- .NET Application Security
- Code Access Security
- .NET Standards Support
- Numeric Types in the .NET Framework
- Working with Strings
- Formatting Strings
- Trimming Character Strings
- Comparing Strings in .NET 2.0
- Arrays and Collections
- Arrays
- Multi-dimensional Arrays
- Jagged Arrays
- Resizing an Array
- ArrayList
- Searching for Items in Collections
- Comparing Items
- Sorting and Binary Search
- Simple Sorting
- Using a Different Comparison Method
- Key-sorting an Array
- Using BinarySearch
- Dictionary Collection Types
- Hashtable
- Hashtable Construction Options
- SortedList
- Queue and Stack
- Collections and Thread Safety
- Type-Safe Collections
- Synchronization
- Official Documentation
- Arrays as Class Members
- Sorting a Multi-Dimensional Array
- Sorting a Multi-Dimensional Array with LINQ
- File I/O (System.IO)
- Working with File Names
- Using the File System
- Working with Files and Directories
- Monitoring the File System
- Working with Streams
- Working with Text Encodings
- Working with Date and Time
- Extending the DateTime Class
- Fun with Dates
- Exceptions
- Delegates
- Events
- Asynchronous Programming
- Asynchronous File I/O
- Timers
- Random Numbers
- Cryptographically Secure Random Numbers
- Serialization
- MultiThreading (System.Threading)
- Multi-Threading Overview
- The Managed Thread Pool
- Managed Threading
- Thread Synchronization
- Synchronizing Data Access
- Trace Debugging
- Tracing in .NET 2.0
- ASP.NET Trace
- Validating User Input in ASP.NET Web Pages
- Event Logging
- Monitoring Application Performance
- Accessing the Registry
- Accessing Environment Information
- Environment Variables in .NET 2.0
- Managing Windows Forms Applications
- Working with Email
- Working with Graphics
- Animating a Background
- Working with Images
- Drawing Cycloid Curves
- Simulating the Spirograph
- Building International Web Applications
- .NET Compact Framework
- Mobile Web Development with ASP.NET
- Speech Technologies
- Microsoft MapPoint Web Service
- Working with Typed DataSets
- Using Relationships in DataSets
- DataColumn Expressions
- Playing Simple Sounds
- Playing Sounds with .NET 2.0
- Returning an Image in a Web Page
- RSS
- Best Practices Project Structure
- Best Practices Application Blocks
- The Data Access Application Block
- The Exception Management Application Block
- Best Practices — Performance
- Best Practices — Performance and Scalability
- Best Practices - Testing
- Reading the Tea Leaves, 2005
- Predictions: A Look Back at 2005, and a Look Ahead to 2006
- .NET Downloads
- Application Deployment Overview
- Application Deployment — Versioning
- Application Deployment — Version Policy
- Application Deployment — Packaging and Distribution
- .NET Remoting Overview
- A Remoting Demonstration
- Remoting Configuration
- Remoting: Lifetimes and Leases
- Remoting: Other Issues
- Attributes
- Writing Custom Attributes
- Accessing Attributes in Code
- Reflection
- Class Design: Inheritance, Interface, or Composition?
- The TriTryst Game
- Console Applications in .NET 2.0
- New File I/O Methods in .NET 2.0
- Building Projects with MSBuild
- Unmanaged Callbacks in .NET 2.0
- Timer Troubles
- Non-Rectangular Windows Forms
- Windows Forms Transparency
- 10 Things I Hate About Visual Basic
- 10 Things I Hate About C#
- Background Processing with Idle Time
- Scaling Windows Forms
- Reading and Writing Binary Data
- New Memory Management Functions in .NET 2.0
- Compatibility Between .NET 1.1 and .NET 2.0
- Managed Debugging Assistants in .NET 2.0
- XDir: A Program for Viewing Directory Sizes
- The Microsoft.VisualBasic Namespace
- Operator Overloading
- Working with GPS Data
- Hidden Visual Studio Tools
- .NET 3.0
- The .NET 2.0 Stopwatch Class
- Nullable Types
- Drawing Rotated Text
- Unsafe Code
- Other .NET Languages
- Compiler Directives
- Safe Handles
- Predictions, 2007 Edition
- New Features in C# 3.0
- Generics
- Network Client Programming
- On the Misuse of Exceptions
- Maximum Object Size in .NET
- More on Maximum Object Sizes
- Keyed Collection Memory Limitations
- Matching String Endings
- Allocating Small Data Structures
- Grumbling About Limitations
- Some Thoughts on the Nature of What We Do
- Working with Predicates in Collections
- Working with DataReaders
- Outputting XML with XmlWriter
- Writing XML Data
- Working with Compression
- Another Look at Compressed Streams
- Compressing a Very Large File
- Canonical URIs
- Constructing URIs
- Using OneWayAttribute for Remote Calls
- Selecting a Garbage Collector
- Linked List
- Linked List Application - The MRU List
- Auto-implemented Properties in C#
- The HashSet Collection
- Looking Ahead: 2018
- An Experiment in Optimization
- A Larger Integer
- Extension Methods
- Language Integrated Query (LINQ)
- Variable Length Parameter Lists
- The ReaderWriterLockSlim Synchronization Primitive
- Sorting a Text File
- Sorting a Large Text File
- Using ListView with Large Data Sets
- LINQ One-Liners
- Regular Expression Optimization
- Random File I/O
- Computing the Size of a Structure
- More on Computing Structure Sizes
- UnmanagedMemoryStream
- Dynamically Loading Code
- Building a String Table
- Delegates Versus Function Pointers
- Visual Studio Editor Features
- A Simple Profile Timer
- New Features in C# 4.0
- IEnumerator or IList?
- New Features in .NET 4.0
- Set Operations with IEnumerable and HashSet
- Using File Locks
- Extending Object Functionality
- Clearing a HashSet
- When Hash Codes Matter
- Parsing Command Line Options
- Creating a Single-Instance Program
- Asynchronous Windows Forms Events
- The BackgroundWorker Component
- Fixing a Dumb Mistake
- Thinking About Multi-Threaded Programs
- JavaScript Object Notation
- Useful .NET-related Sites
- Markov Models
- Building an Order 0 Markov Model
- Higher Order Markov Models
- Webmaster's Guide to robots.txt
- An Overview of the Parallel Extensions to .NET
- Parallel Extensions Synchronization Objects
- Thread Safe Collections
- A Bug and a Conundrum
- Another Bug and an Answer
- Task Parallel Library
- Good and Bad Ideas in C#
- Parallel LINQ
- Copying Large Files
- Replacing File.Copy
- Learning from Our Mistakes
- Symbolic Links
- There Is No Easy Fix
- Tracking Hurricanes
- Examining Hurricane Data
- Searching for Multiple Strings
- Simple JSON Processing
- Aho-Corasick String Searching
- Writing a Web Crawler
- Web Crawler Politeness
- Source Control Management
- Subversion
- Communicating with Datagrams
- Fun with Actions and Funcs New
- The Future of Media
- The Importance of Metadata
- Of Comparison and IComparer
- IComparer, Comparer, IComparable, Oh My!
- Comparing Generic Types New
- A Simple HTTP Server New
- Informit Reference Library
Collections and Thread Safety
Last updated Jan 1, 2004.
The default behavior of all the collection classes is not generally thread safe. Although any number of threads can read a collection simultaneously, a single thread modifying the collection can cause undefined behavior for any other threads that are accessing it. The Hashtable class guarantees thread safety for a single writer and multiple readers, but if multiple writers are required, the same rules apply as for all the other collection types.
The .NET Framework SDK documentation identifies three primary ways to make collections thread safe:
Create a thread-safe wrapper using the Synchronized method, and access the collection exclusively through that wrapper.
If the class does not have a Synchronized method, derive from the class and implement a Synchronized method using the SyncRoot property.
Use a locking mechanism, such as the lock statement in C# (SyncLock in Visual Basic), on the SyncRoot property when accessing the collection.
lock (SyncLock in Visual Basic) is the easiest and most effective way to guarantee thread safety. Lock is most useful when enumerating a collection. Enumerating through a collection is inherently not thread-safe, and will throw an exception if the collection is modified at any point during the enumeration. To prevent any other thread from modifying the collection, you lock the collection first, like this:
C#
SortedList myCollection = new SortedList();
// code that adds items to the collection
// lock the collection and enumerate it
lock (myCollection.SyncRoot)
{
foreach (Object item in myCollection)
{
// insert your enumeration code here
}
}
Visual Basic
Dim myCollection as New SortedList()
' code that adds items to the collection
' lock the collection and enumerate it
Dim item as Object
SyncLock myCollection.SyncRoot
For Each item In myCollection
' insert your enumeration code here
Next item
End SyncLock
As effective as it is, lock isn't very friendly. When a thread acquires a lock in this manner, no other thread can access the collection. You should use lock only when performing an operation that must have exclusive access to the collection, and you should release the lock as soon as possible.
Synchronize is a much friendlier way to allow multiple threads access to a collection. It is a cooperative technique that requires each thread to follow the rules. Fortunately, those rules are very simple: rather than access the shared collection object, each thread obtains a reference to a synchronized collection object and performs all access through that reference. All it takes is a single call to the static Synchronized method, as shown below.
C#
Hashtable myHt = new Hashtable();
// code that adds items to the Hashtable
// obtain a synchronized wrapper around the Hashtable
Hashtable mySyncHt = Hashtable.Synchronize(myHt);
// all access to mySyncHt is synchronized
Console.WriteLine("myHt is {0}" ?
myHt.IsSynchronized ? "synchronized" : "not synchronized");
Console.WriteLine("mySyncHt is {0}" ?
mySyncHt.IsSynchronized ? "synchronized" : "not synchronized");
Visual Basic
Dim myHt as New Hashtable()
' code that adds items to the Hashtable
' obtain a synchronized wrapper around the Hashtable
Dim mySyncHt as Hashtable = Hashtable.Synchronize(myHt)
' all access to mySyncHt is synchronized
Dim msg As String
If myHt.IsSynchronized then
msg = "synchronized"
Else
msg = "not synchronized"
End If
Console.WriteLine("myHt is {0}", msg)
If mySyncHt.IsSynchronized then
msg = "synchronized"
Else
msg = "not synchronized"
End If
Console.WriteLine("mySyncHt is {0}", msg)
The IsSynchronized property returns true if the collection is synchronized.
It's worth repeating that using synchronized lists is cooperative. Nothing prevents a thread from accessing the list through the non-synchronized reference. But if you're careful to code the classes that use the list so all access it through the Synchronized reference, all will be fine.
In practice, you will use a combination of Synchronize and lock to provide thread-safe access to your collections. Most often, you'll use Synchronize during updates to prevent multiple threads from trying to modify the collection at the same time, and lock when you have a longer operation that requires exclusive access.
The other technique for providing thread-safe access involves creating a derived class and implementing your own Synchronize method. That is covered in the next section (next week), when we take a look at creating your own collection classes.



Account Sign In
View your cart