Csharp/CSharp Tutorial/Thread/Monitor

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

Coordinate two threads using Monitor

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();
    }
}
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

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" );
  }
}

Monitor: Enter and Exit

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 );
    }
      
  }
}
in monotor
in monotor

Monitor Pool

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 );
      }
    }
  }
}

Monitor: try to enter

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);
      }
    }
  }
}

Throw exception between Monitor.Enter and Montor.Exit

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();
    }
}

Use Monitors

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);
  }
}

Use Monitor to control more than one Threads

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;
  }
}
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

//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"); 
  } 
}
Tick Tock
Tick Tock
Tick Tock
Tick Tock
Tick Tock
Clock Stopped

Using A Monitor

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);
        }
    }
}