CHAPTER 19 MULTITHREADED, PARALLEL, AND ASYNC PROGRAMMING
shared resources. As you would guess, the System.Threading namespace provides a number of
synchronization-centric types. The C# programming language also provides a particular keyword for the
very task of synchronizing shared data in multithreaded applications.
Synchronization Using the C# lock Keyword
The first technique you can use to synchronize access to shared resources is the C# lock keyword. This
keyword allows you to define a scope of statements that must be synchronized between threads. By
doing so, incoming threads cannot interrupt the current thread, thus preventing it from finishing its
work. The lock keyword requires you to specify a token (an object reference) that must be acquired by a
thread to enter within the lock scope. When you are attempting to lock down a private instance-level
method, you can simply pass in a reference to the current type, as follows:
private void SomePrivateMethod()
{
// Use the current object as the thread token.
lock(this)
{
// All code within this scope is thread safe.
}
}
However, if you are locking down a region of code within a public member, it is safer (and a best
practice) to declare a private object member variable to serve as the lock token, like so:
public class Printer
{
// Lock token.
private object threadLock = new object();
public void PrintNumbers()
{
// Use the lock token.
lock (threadLock)
{
...
}
}
}
In any case, if you examine the PrintNumbers() method, you can see that the shared resource the
threads are competing to gain access to is the console window. Therefore, if you scope all interactions
with the Console type within a lock scope, as follows:
public void PrintNumbers()
{
// Use the private object lock token.
lock (threadLock)
{
// Display Thread info.
Console.WriteLine("-> {0} is executing PrintNumbers()",
Thread.CurrentThread.Name);
723