|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
The following article is an excerpt from chapter 5 of the book Practical .NET2 and C#2. Contents
IntroductionThe The Enter() and Exit() methodsThe
The following example illustrate how to use these two methods to protect a static field named Example1.csusing System.Threading;
class Program {
static long counter = 1;
static void Main() {
Thread t1 = new Thread( f1 );
Thread t2 = new Thread( f2 );
t1.Start(); t2.Start(); t1.Join(); t2.Join();
}
static void f1() {
for (int i = 0; i < 5; i++){
Monitor.Enter( typeof( Program ) );
try{
counter *= counter;
}
finally{ Monitor.Exit( typeof( Program ) ); }
System.Console.WriteLine("counter^2 {0}", counter);
Thread.Sleep(10);
}
}
static void f2() {
for (int i = 0; i < 5; i++){
Monitor.Enter( typeof( Program ) );
try{
counter *= 2;
}
finally{ Monitor.Exit( typeof( Program ) ); }
System.Console.WriteLine("counter*2 {0}", counter);
Thread.Sleep(10);
}
}
}
It is tempting to write Notice that the square and doubling operations are not commutative and thus the final value of The lock C# keywordThe C# language presents the Example2.csusing System.Threading;
class Program {
static long counter = 1;
static void Main() {
Thread t1 = new Thread(f1);
Thread t2 = new Thread(f2);
t1.Start(); t2.Start(); t1.Join(); t2.Join();
}
static void f1() {
for (int i = 0; i < 5; i++){
lock( typeof(Program) ) { counter *= counter; }
System.Console.WriteLine("counter^2 {0}", counter);
Thread.Sleep(10);
}
}
static void f2() {
for (int i = 0; i < 5; i++){
lock( typeof(Program) ) { counter *= 2; }
System.Console.WriteLine("counter*2 {0}", counter);
Thread.Sleep(10);
}
}
}
As with ...
lock( typeof( Program ) )
counter *= counter;
...
The use of the The SyncRoot patternAs with the previous examples, we generally use the Example3.csclass Foo {
private static object staticSyncRoot = new object();
private object instanceSyncRoot = new object();
public static void StaticFct() {
lock ( staticSyncRoot ) { /*...*/ }
}
public void InstanceFct() {
lock ( instanceSyncRoot ) { /*...*/ }
}
}
The Example4.csusing System.Collections.Generic;
using System.Collections;
public class Program {
public static void Main() {
List
Thread-safe classesA thread-safe class is a class where each instance cannot be accessed by more than one thread at a time. To create such a thread-safe class, you simply need to apply the SyncRoot pattern that we have seen, to its methods. A good way not to burden the code of a class that we wish to be thread-safe is to provide a thread-safe wrapper derived class like this: Example5.csclass Foo {
private class FooSynchronized : Foo {
private object syncRoot = new object();
private Foo m_Foo;
public FooSynchronized( Foo foo ) { m_Foo = foo; }
public override bool IsSynchronized { get { return true; } }
public override void Fct1(){lock( syncRoot ) { m_Foo.Fct1(); } }
public override void Fct2(){lock( syncRoot ) { m_Foo.Fct2(); } }
}
public virtual bool IsSynchronized { get { return false; } }
public static Foo Synchronized(Foo foo){
if( ! foo.IsSynchronized )
return new FooSynchronized( foo );
return foo;
}
public virtual void Fct1() { /*...*/ }
public virtual void Fct2() { /*...*/ }
}
The Monitor.TryEnter() methodpublic static bool TryEnter(object [,int] )
This method is similar to Example6.csusing System.Threading;
class Program {
private static object staticSyncRoot = new object();
static void Main() {
// Comment this line to test the case where the
// ‘TryEnter()’ method returns true.
Monitor.Enter( staticSyncRoot );
Thread t1 = new Thread(f1);
t1.Start(); t1.Join();
}
static void f1() {
if( ! Monitor.TryEnter( staticSyncRoot ) )
return;
try {
// ...
}
finally {
Monitor.Exit( staticSyncRoot );
}
}
}
The Wait(), Pulse(), and PulseAll() methods of the Monitor classpublic static bool Wait( object [,int] )
public static void Pulse( object )
public static void PulseAll( object )
The
If The following program illustrates this functionality through two threads Example7.csusing System.Threading;
public class Program {
static object ball = new object();
public static void Main() {
Thread threadPing = new Thread( ThreadPingProc );
Thread threadPong = new Thread( ThreadPongProc );
threadPing.Start(); threadPong.Start();
threadPing.Join(); threadPong.Join();
}
static void ThreadPongProc() {
System.Console.WriteLine("ThreadPong: Hello!");
lock ( ball )
for (int i = 0; i < 5; i++){
System.Console.WriteLine("ThreadPong: Pong ");
Monitor.Pulse( ball );
Monitor.Wait( ball );
}
System.Console.WriteLine("ThreadPong: Bye!");
}
static void ThreadPingProc() {
System.Console.WriteLine("ThreadPing: Hello!");
lock ( ball )
for(int i=0; i< 5; i++){
System.Console.WriteLine("ThreadPing: Ping ");
Monitor.Pulse( ball );
Monitor.Wait( ball );
}
System.Console.WriteLine("ThreadPing: Bye!");
}
}
This program displays the following (in a non-deterministic way): ThreadPing: Hello!
ThreadPing: Ping
ThreadPong: Hello!
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Bye!
The
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||