Csharp/CSharp Tutorial/Thread/Monitor — различия между версиями

Материал из .Net Framework эксперт
Перейти к: навигация, поиск
м (1 версия)
 
(нет различий)

Текущая версия на 15:20, 26 мая 2010

Coordinate two threads using Monitor

<source lang="csharp">using System; using System.Threading; public class MainClass {

   static private int counter = 0;
   static private object theLock = new Object();
   static private void ThreadFunc1() {
       lock( theLock ) {
           for( int i = 0; i < 50; ++i ) {
               Monitor.Wait( theLock, Timeout.Infinite );
               Console.WriteLine( "{0} from Thread {1}", ++counter, Thread.CurrentThread.GetHashCode() );
               Monitor.Pulse( theLock );
           }
       }
   }
   static private void ThreadFunc2() {
       lock( theLock ) {
           for( int i = 0; i < 50; ++i ) {
               Monitor.Pulse( theLock );
               Monitor.Wait( theLock, Timeout.Infinite );
               Console.WriteLine( "{0} from Thread {1}", ++counter, Thread.CurrentThread.GetHashCode() );
           }
       }
   }
   static void Main() {
       Thread thread1 = new Thread( new ThreadStart(ThreadFunc1) );
       Thread thread2 = new Thread( new ThreadStart(ThreadFunc2) );
       thread1.Start();
       thread2.Start();
   }

}</source>

1 from Thread 3
2 from Thread 4
3 from Thread 3
4 from Thread 4
5 from Thread 3
6 from Thread 4
7 from Thread 3
8 from Thread 4
9 from Thread 3
10 from Thread 4
11 from Thread 3
12 from Thread 4
13 from Thread 3
14 from Thread 4
15 from Thread 3
16 from Thread 4
17 from Thread 3
18 from Thread 4
19 from Thread 3
20 from Thread 4
21 from Thread 3
22 from Thread 4
23 from Thread 3
24 from Thread 4
25 from Thread 3
26 from Thread 4
27 from Thread 3
28 from Thread 4
29 from Thread 3
30 from Thread 4
31 from Thread 3
32 from Thread 4
33 from Thread 3
34 from Thread 4
35 from Thread 3
36 from Thread 4
37 from Thread 3
38 from Thread 4
39 from Thread 3
40 from Thread 4
41 from Thread 3
42 from Thread 4
43 from Thread 3
44 from Thread 4
45 from Thread 3
46 from Thread 4
47 from Thread 3
48 from Thread 4
49 from Thread 3
50 from Thread 4
51 from Thread 3
52 from Thread 4
53 from Thread 3
54 from Thread 4
55 from Thread 3
56 from Thread 4
57 from Thread 3
58 from Thread 4
59 from Thread 3
60 from Thread 4
61 from Thread 3
62 from Thread 4
63 from Thread 3
64 from Thread 4
65 from Thread 3
66 from Thread 4
67 from Thread 3
68 from Thread 4
69 from Thread 3
70 from Thread 4
71 from Thread 3
72 from Thread 4
73 from Thread 3
74 from Thread 4
75 from Thread 3
76 from Thread 4
77 from Thread 3
78 from Thread 4
79 from Thread 3
80 from Thread 4
81 from Thread 3
82 from Thread 4
83 from Thread 3
84 from Thread 4
85 from Thread 3
86 from Thread 4
87 from Thread 3
88 from Thread 4
89 from Thread 3
90 from Thread 4
91 from Thread 3
92 from Thread 4
93 from Thread 3
94 from Thread 4
95 from Thread 3
96 from Thread 4
97 from Thread 3
98 from Thread 4
99 from Thread 3
100 from Thread 4

Increment Monitor

<source lang="csharp">using System; using System.Threading; public class MainClass {

 private static Object locker = new Object();
 private static int count = 0;
 public int IncrementCount()
 {
   int rc;
   lock( locker )
   {
     rc = ++count;
   }
   return rc;
 }
 public void DoCount()
 {
   for( int i = 0; i < 10; i++ )
   {
     System.Console.WriteLine( "Thread {0}: count = {1}", Thread.CurrentThread.Name, IncrementCount() );
     Thread.Sleep( 0 );
   }
 }
 [STAThread]
 static void Main(string[] args)
 {
   int limit = 10;
   Thread[] t = new Thread[ limit ];
   for(int k = 0; k < limit; k++ )
   {
     MainClass b = new MainClass();
     t[ k ] = new Thread( new ThreadStart( b.DoCount ) );
     t[ k ].Name = "Thread " + k;
   }
   for(int k = 0; k < limit; k++ )
   {
     t[ k ].Start();
   }
   for(int k = 0; k < limit; k++ )
   {
     t[ k ].Join();
   }
   System.Console.WriteLine( "All threads complete" );
 }

}</source>

Monitor: Enter and Exit

<source lang="csharp">using System; using System.Threading; class MainClass {

 [STAThread]
 static void Main(string[] args)
 {
     int r = 0;
   object t = new object();
   
   try
   {
     Monitor.Enter( t );
     r++;
   }
   finally
   {
     Monitor.Exit( t );
   }
     
 }

}</source>

in monotor
in monotor

Monitor Pool

<source lang="csharp">using System; using System.Threading; class MainClass {

 private const int threads = 4;
 private const int workitems = 50;
 private static Object locker = new Object();
 static void Worker()
 {
   while( true )
   {
     lock( locker )
     {
       Monitor.Wait( locker );
     }
     System.Console.WriteLine( "{0} doing work", Thread.CurrentThread.Name );
     Thread.Sleep( 100 );
   }
 }
 [STAThread]
 static void Main(string[] args)
 {
   Thread[] t = new Thread[ threads ];
   for( int k = 0; k < threads; k++ )
   {
     t[ k ] = new Thread( new ThreadStart( Worker ) );
     t[ k ].Name = "Worker " + k;
     t[ k ].IsBackground = true;
     t[ k ].Start();
   }
   for( int i = 0; i < workitems; i ++ )
   {
     Thread.Sleep( 1000 );
     lock( locker )
     {
       Monitor.Pulse( locker );
     }
   }
 }

}</source>

Monitor: try to enter

<source lang="csharp">using System; using System.Threading; class MainClass {

 [STAThread]
 static void Main(string[] args)
 {
   object t = new object();
   int r = 0;
   try
   {
     if ( Monitor.TryEnter( t, 250 ) )
     {
       r++;
     }
   }
   finally
   {
     try
     {
       Monitor.Exit( t );
     }
     catch( SynchronizationLockException sle )
     {
       Console.WriteLine(sle);
     }
   }
 }

}</source>

Throw exception between Monitor.Enter and Montor.Exit

<source lang="csharp">using System; using System.Threading;

class Database {

   public void SaveData(string text)
   {
       Console.WriteLine("[SaveData] Started");
  
       Monitor.Enter(this);
       Console.WriteLine("[SaveData] Working");
  
       throw new Exception("ERROR!");
  
       for (int i = 0; i < 50; i++)
       {
           Thread.Sleep(100);
           Console.Write(text);
       }
       Monitor.Exit(this);
  
       Console.WriteLine("\n[SaveData] Ended");
   }

}

class ThreadMonitor3App {

   public static Database db = new Database();
  
   public static void WorkerThreadMethod1()
   {
       Console.WriteLine("[WorkerThreadMethod1] Started");
  
       Console.WriteLine("[WorkerThreadMethod1] " +
           "Calling Database.SaveData");
  
       try
       {
           db.SaveData("x");
       }
       catch{}
  
       Console.WriteLine("[WorkerThreadMethod1] Finished");
   }
  
   public static void WorkerThreadMethod2()
   {
       Console.WriteLine("[WorkerThreadMethod2] Started");
  
       Console.WriteLine("[WorkerThreadMethod2] " +
           "Calling Database.SaveData");
       try
       {
           db.SaveData("o");
       }
       catch{}
  
       Console.WriteLine("[WorkerThreadMethod2] Finished");
   }
  
   public static void Main()
   {
       ThreadStart worker1 = new ThreadStart(WorkerThreadMethod1);
       ThreadStart worker2 = new ThreadStart(WorkerThreadMethod2);
  
       Thread t1 = new Thread(worker1);
       Thread t2 = new Thread(worker2);
  
       t1.Start();
       t2.Start();
  
       Console.ReadLine();
   }

}</source>

Use Monitors

<source lang="csharp">using System; using System.Collections; using System.Threading; class MainClass {

 public static ArrayList MyList = new ArrayList();
 
 static void Main(string[] args)
 {
     Thread ThreadOne = new Thread(new ThreadStart(MonitorExample));
   ThreadOne.Start();
 }
 static void MonitorExample()
 {
   Monitor.Enter(MyList);
   MyList.Add("a value");
   Monitor.Exit(MyList);
 }

}</source>

Use Monitor to control more than one Threads

<source lang="csharp">using System; using System.Threading; class MyClass {

 private int counter;
 public void DoSomeWork()
 {
   lock(this)
   {
     counter++;
     // Do the work.
     for(int i = 0; i < 5; i++)
     {
       Console.WriteLine("counter: {0}, i: {1}, current thread: {2}",
         counter, i, Thread.CurrentThread.Name);
       Thread.Sleep(1000);
     }
   }
 }

} public class MainClass {

 public static int Main(string[] args)
 {
   MyClass w = new MyClass();
   Thread workerThreadA = new Thread(new ThreadStart(w.DoSomeWork));
   workerThreadA.Name = "A";
   Thread workerThreadB = new Thread(new ThreadStart(w.DoSomeWork));
   workerThreadB.Name = "B";
   Thread workerThreadC = new Thread(new ThreadStart(w.DoSomeWork));
   workerThreadC.Name = "C";
   // Now start each one.
   workerThreadA.Start();
   workerThreadB.Start();
   workerThreadC.Start();
   
   return 0;
 }

}</source>

counter: 1, i: 0, current thread: A
counter: 1, i: 1, current thread: A
counter: 1, i: 2, current thread: A
counter: 1, i: 3, current thread: A
counter: 1, i: 4, current thread: A
counter: 2, i: 0, current thread: B
counter: 2, i: 1, current thread: B
counter: 2, i: 2, current thread: B
counter: 2, i: 3, current thread: B
counter: 2, i: 4, current thread: B
counter: 3, i: 0, current thread: C
counter: 3, i: 1, current thread: C
counter: 3, i: 2, current thread: C
counter: 3, i: 3, current thread: C
counter: 3, i: 4, current thread: C

Use Wait() and Pulse() to create a ticking clock

<source lang="csharp">//C# 2.0 The Complete Reference using System; using System.Threading; class TickTock {

 public void tick(bool running) { 
   lock(this) { 
     if(!running) { // stop the clock 
       Monitor.Pulse(this); // notify any waiting threads 
       return; 
     } 

     Console.Write("Tick "); 
     Monitor.Pulse(this); // let tock() run 
     Monitor.Wait(this); // wait for tock() to complete 
   } 
 } 

 public void tock(bool running) { 
   lock(this) { 
     if(!running) { // stop the clock 
       Monitor.Pulse(this); // notify any waiting threads 
       return; 
     } 

     Console.WriteLine("Tock"); 
     Monitor.Pulse(this); // let tick() run 

     Monitor.Wait(this); // wait for tick() to complete 
   } 
 } 

}

class MyThread {

 public Thread thrd; 
 TickTock ttOb; 

 // Construct a new thread. 
 public MyThread(string name, TickTock tt) { 
   thrd = new Thread(this.run); 
   ttOb = tt; 
   thrd.Name = name; 
   thrd.Start();  
 } 

 // Begin execution of new thread. 
 void run() { 
   if(thrd.Name == "Tick") { 
     for(int i=0; i<5; i++) ttOb.tick(true); 
     ttOb.tick(false); 
   } 
   else { 
     for(int i=0; i<5; i++) ttOb.tock(true); 
     ttOb.tock(false); 
   } 
 } 

}

class TickingClock {

 public static void Main() { 
   TickTock tt = new TickTock(); 
   MyThread mt1 = new MyThread("Tick", tt); 
   MyThread mt2 = new MyThread("Tock", tt); 

   mt1.thrd.Join(); 
   mt2.thrd.Join(); 
   Console.WriteLine("Clock Stopped"); 
 } 

}</source>

Tick Tock
Tick Tock
Tick Tock
Tick Tock
Tick Tock
Clock Stopped

Using A Monitor

<source lang="csharp">using System; using System.Collections.Generic; using System.Text; using System.Threading; class Tester {

   static long counter = 0;
   //new Tester();
   static void Main()
   {
       Thread[] myThreads = {
              new Thread( new ThreadStart(Decrementer) ),
              new Thread( new ThreadStart(Incrementer) )              
           };
       int ctr = 1;
       foreach (Thread myThread in myThreads)
       {
           myThread.IsBackground = true;
           myThread.Start();
           myThread.Name = "Thread" + ctr.ToString();
           ctr++;
           Console.WriteLine("Started thread {0}", myThread.Name);
           Thread.Sleep(50);
       }
       foreach (Thread myThread in myThreads)
       {
           myThread.Join();
       }
   }
   static void Decrementer()
   {
       try
       {
           Monitor.Enter(counter);
           if (counter < 10)
           {
               Console.WriteLine(Thread.CurrentThread.Name);
               Console.WriteLine(counter);
               Monitor.Wait(counter);
           }
           while (counter > 0)
           {
               long temp = counter;
               temp--;
               Thread.Sleep(1);
               counter = temp;
               Console.WriteLine(Thread.CurrentThread.Name);
               Console.WriteLine(counter);
           }
       }
       finally
       {
           Monitor.Exit(counter);
       }
   }
   static void Incrementer()
   {
       try
       {
           Monitor.Enter(counter);
           while (counter < 10)
           {
               long temp = counter;
               temp++;
               Thread.Sleep(1);
               counter = temp;
               Console.WriteLine(Thread.CurrentThread.Name);
               Console.WriteLine(counter);
           }
           Monitor.Pulse(counter);
       }
       finally
       {
           Monitor.Exit(counter);
       }
   }

}</source>