Multithreading with C#
Pages: 1, 2, 3, 4
Enter/TryEnter/Exit
![]() |
Related Tutorials: Building Web Services with .NET -- One of the key motivations behind .NET is the move towards web services. This tutorial provides an overview of the rich support in the Microsoft .NET Framework for building web services and networked applications. Microsoft .NET and the Common Language Runtime -- This tutorial provides an overview of the .NET Framework, then delves into the Common Language Runtime and what it offers to developers building & deploying modern applications. |
To obtain a lock on a variable in Java, you just need to surround
the code with the synchronized keyword specifying the object that
the program should attempt to acquire a lock on. Once a thread has
started to execute code in the synchronized block, it is guaranteed
to have already received a monitor lock on the object being
synchronized on -- likewise, once a thread has left the block, it
will have released the lock on the object. We have seen that C# has
a similar construct called lock that operates on reference types.
In addition to the lock construct, C# has provided access to its
internal methods to acquire and release locks: Monitor.Enter( object
obj )and Monitor.Exit( object obj ). Using these methods can buy a
programmer the same benefits as using the lock construct, but it can
also provide more elaborate locking abilities, such as being able to
lock variables in one method and have them released at different
times or different points in the code, depending on the code path.
A call to System.Threading.Monitor.Enter on the object to
synchronize on will cause C# to either obtain the lock on the
object, or block if another thread is currently holding lock (it
will not block if a Thread already holding an object's lock attempts
to acquire it again -- however, a programmer should ensure that a
lock is released the same amount of times it is acquired). It
should be noted that calling Interrupt() on a Thread which is
blocking on an Enter to a lock will cause the method to unblock and
throw a System.Threading.ThreadIntrerruptedException. Releasing a
lock is easily done with the Monitor.Exit method -- this method will
throw a System.Threading.SynchronizationLockException if it does not
already own the lock on the object it is attempting to release.
What Java is lacking (and what C# has) is the ability to attempt to enter a synchronized code segment without blocking on the acquisition of the lock. C#'s Monitor class not only contains the Enter method, which blocks until it can be assured that it will be the only thread in the block, but it also contains a TryEnter method, which will either obtain a lock (optionally blocking for a given amount of time) or return with a return value of false, signifying that it cannot get a lock on the object.
Atomic Operations
As more syntactic sugar, the System.Threading.Interlocked class
provides the ability for a program to synchronize access to
variables that are shared amongst Threads. C# manages this by
abstracting a few basic operations into "atomic" or non-splittable
operations. To explain the problem that is being solved, take the
following Java code block:
public static int x = 1;
public static void increment() {
x = x + 1;
}
If we have increment() called by two different threads
simultaneously, x could be equal to either 2 or 3 at the end. This
can happen with code from both threads interweaving with each other
while looking up the variable of x and incrementing it before
setting x again; both threads could read x as 1 before any thread
has the chance to increment it and set x with the new value.
In both languages we can synchronize access to the x variable so
that the threads can stay out of each other's way, but C# provides a
cleaner solution through the use of the Interlocked class.
Interlocked has a few methods such as Increment( ref int location )
and Decrement( ref int location ) that can take an integer,
increment it, and return its new value all in one uninterruptable
step, instead of explicitly creating a separate object that the code
can synchronize on, such as this example in Java:
public static Object locker = ...
public static int x = 1;
public static void increment() {
synchronized( locker ) {
x = x + 1;
}
}
C#'s Interlocked class can do the same operation with
public static int x = 1;
public static void Increment() {
Interlocked.Increment( ref x );
}
Interlocked also contains a method named Exchange, which allows for the setting of a variable from another variable in a single step.
ThreadPools
A lot of threaded applications create threads that spend a majority
of their time in a waiting state waiting for a certain condition
(key press, new I/O input, etc.). C# provides a single
System.Threading.ThreadPool object to help with this problem --
using the ThreadPool and an event-based programming paradigm, the program can register a System.Threading.WaitHandle object
(WaitHandles are C#'s object model for the wait and notify paradigm
of coding) and a System.Threading.WaitOrTimerCallback delegate. Instead of having a full-fledged Thread waiting for the WaitHandle
to release, the ThreadPool will monitor all the WaitHandles
registered with it and then call the appropriate WaitOrTimerCallback
delegate method when the WaitHandle has been released.
In this article we have seen the abstractions that C# provides for threaded and parallel operations. Most are similar to Java -- C# provides a Thread object that can run a provided method while also providing ways to synchronize access to certain blocks of code. As usual, C# also provides a few more syntactic sugars (or in some cases, exposes the underlying synchronization base) that Java programmers may find useful. By this point, we have covered most of what Java programmers need to get started in writing trivial to intermediate applications; we have focused on C# syntax, I/O, and now, threading. All that is really left will be covered in the next article: graphical applications.
Raffi Krikorian makes a career of hacking everything and anything. Professionally, he is the founding partner at Synthesis Studios: a technological design and consulting firm that orchestrates his disjointed train of thought.
Return to ONJava.com.
