C # various Synchronization Methods: lock, Monitor, Mutex, Semaphore, Interlocked, ReaderWriterLock, AutoResetEvent, ManualResetEvent,
Take a look at the organizational structure:
System. Object
System. externalbyrefobject
System. Threading. WaitHandle
System. Threading. Mutex
System. Threading. Semaphore
System. Threading. EventWaitHandle
System. Threading. ManualResetEvent
System. Threading. AutoResetEvent
System. Object
System. Threading. Interlocked
System. Threading. Monitor
System. Threading. ReaderWriterLock
1. The lock keyword is actually encapsulation of the Enter () and Exit () Methods of the Monitor class. Use the try... catch... finally statement block to ensure that the Monitor. Exit () method is executed after the lock statement block is complete to release the mutex lock. The following two sections of code are equivalent:
lock(locker){ //do something}
View Code
Monitor.Enter(locker);try{ // do something}finally{ Monitor.Exit(locker);}
View Code
2,
The Monitor class grants an object lock to a single thread to control access to the object. Object locks provide the ability to restrict access to critical zones. When a thread has an object lock, no other thread can obtain the lock. You can also use Monitor to ensure that no other thread is allowed to access the application code section being executed by the lock owner, unless another thread is using another lock object to execute the code. Through the analysis of the lock keyword, we know that lock is an encapsulation of the Enter and Exit of Monitor, and it is more concise to use. Therefore, the Enter () and Exit () of the Monitor class () the combination of methods can be replaced by the lock keyword.
Common Methods of the Monitor class:
TryEnter ():
It can effectively solve problems such as long-term crashes. If TryEnter is used in an environment where a concurrency occurs frequently and lasts for a long time, it can effectively prevent deadlocks or long waits. For example, you can set a waiting time bool gotLock = Monitor. TryEnter (myobject, 1000) so that the current thread can decide whether to continue the following operations based on the returned bool value after waiting for 1000 seconds.
Wait ():
Release the lock on the object to allow other threads to lock and access the object. When other threads access an object, the calling thread will wait. The pulse signal is used to notify the waiting thread of changes to the object state.
Pulse ():
PulseAll ():
Sends signals to one or more waiting threads. This signal indicates that the status of the waiting thread lock object has changed, and the lock owner is ready to release the lock. Wait for the thread to be placed in the ready queue of the object so that it can finally receive the object lock. Once the thread has a lock, it can check the new State of the object to see if it has reached the desired state. Note: The Pulse, PulseAll, and Wait methods must be called from the synchronized code block.
Static object locker = new object (); static bool isHave = false; static void Produce () {lock (locker) {while (true) {// if a product already exists, then wait until the consumption is completed if (isHave) Monitor. wait (locker); Console. writeLine ("produce one"); Thread. sleep (1000); isHave = true; Monitor. pulse (locker) ;}} static void Consume () {lock (locker) {while (true) {// if no product exists, wait until production is complete if (! IsHave) Monitor. Wait (locker); Console. WriteLine ("consume one"); Thread. Sleep (500); isHave = false; Monitor. Pulse (locker );}}}
View Code
Call in the main function:
new Thread(Produce).Start(); new Thread(Consume).Start();
View Code
3. Mutex
public class Test { // Create a new Mutex. The creating thread does not own the // Mutex. private static Mutex mut = new Mutex(); public static void MyThreadProc() { for (int i = 0; i < 2; i++) { UseResource(); } } // This method represents a resource that must be synchronized // so that only one thread at a time can enter. private static void UseResource() { // Wait until it is safe to enter. mut.WaitOne(); Console.WriteLine("{0} has entered the protected area", Thread.CurrentThread.Name); // Place code to access non-reentrant resources here. // Simulate some work. Thread.Sleep(500); Console.WriteLine("{0} is leaving the protected area\r\n", Thread.CurrentThread.Name); // Release the Mutex. mut.ReleaseMutex(); } }
View Code
Test test = new Test(); for (int i = 0; i < 3; i++) { Thread myThread = new Thread(new ThreadStart(Test.MyThreadProc)); myThread.Name = String.Format("Thread{0}", i + 1); myThread.Start(); }
View Code
Mutex can also determine whether a process already exists in the system.
4. Semaphore
static Semaphore sph = new Semaphore(0, 3); static void TProc() { while (true) { if (sph.WaitOne(500, false)) { try { Console.WriteLine("thread" + Thread.CurrentThread.Name + ":enter"); Thread.Sleep(1000); } finally { sph.Release(); Console.WriteLine("thread" + Thread.CurrentThread.Name + ":exit"); } } else { Console.WriteLine("thread" + Thread.CurrentThread.Name + ":time out"); } } }
View Code
Thread t = null; for (int i = 0; i < 2; i++) { t = new Thread(TProc); t.Name = i.ToString(); t.Start(); } Console.WriteLine("main sleep 4s"); Thread.Sleep(4000); sph.Release(2);
View Code
5. The Interlocker class provides atomic operations for variables shared by multiple threads. It is a static class and its main member methods are as follows:
Add: in the form of an atomic operation, Add two integers and replace the first integer with the sum of the two.
Exchange: sets the variable as the specified value in the form of an atomic operation, and returns the previous value
CompareExchange: compare whether two values are equal. If they are equal, replace one of the values.
Equals: Determine whether two Object instances are equal
Increment: increments the value of a specified variable in the form of an atomic operation and stores the result.
Decrement: Decrement the value of the specified variable in the form of an atomic operation and store the result.
Read: returns a 64-bit value loaded as an atomic operation.
Interlocked.CompareExchange(ref obj, new object(), null);
View Code
6. ReaderWriterLock
static ReaderWriterLock rwLock = new ReaderWriterLock();static object locker = new object();static void Main(string[] args){ Thread t = null; for(int i = 0; i < 2;i++) { t = newThread(Writer); t.Name =i.ToString(); t.Start(); } for(int i = 0; i<3;i++) { t = newThread(Reader); t.Name =i.ToString(); t.Start(); } Console.ReadLine();}static void Writer(){ while(true) { try { rwLock.AcquireWriterLock(3000); Console.WriteLine("writer:"+ Thread.CurrentThread.Name + " is enter" + "WriterSeqNum:" +rwLock.WriterSeqNum.ToString()); try { Thread.Sleep(5000); } finally { rwLock.ReleaseWriterLock(); Console.WriteLine("writer:"+ Thread.CurrentThread.Name + " is exit"); } } catch(ApplicationException) { Console.WriteLine("writer:"+ Thread.CurrentThread.Name + " wait time out"); } }}static void Reader(){ while (true) { rwLock.AcquireReaderLock(-1); Console.WriteLine("reader:"+ Thread.CurrentThread.Name + " is enter" + "WriterSeqNum:" +rwLock.WriterSeqNum.ToString()); try { Thread.Sleep(3000); } finally { Console.WriteLine("reader:"+ Thread.CurrentThread.Name + " is exit"); rwLock.ReleaseReaderLock(); } }}
View Code
7. AutoResetEvent automatically resets the event
When constructing an event object, you must specify whether the initialState parameter is True or False to indicate whether the initial state of the event has a signal or no signal.
When an automatic reset event gets a signal, only one thread in the thread waiting for the event changes to a schedulable thread. When the manual reset object gets a signal, all threads waiting for this event become schedulable threads
class Example{ private static AutoResetEvent event_1 = new AutoResetEvent(true); private static AutoResetEvent event_2 = new AutoResetEvent(false); static void Main() { Console.WriteLine("Press Enter to create three threads and start them.\r\n" + "The threads wait on AutoResetEvent #1, which was created\r\n" + "in the signaled state, so the first thread is released.\r\n" + "This puts AutoResetEvent #1 into the unsignaled state."); Console.ReadLine(); for (int i = 1; i < 4; i++) { Thread t = new Thread(ThreadProc); t.Name = "Thread_" + i; t.Start(); } Thread.Sleep(250); for (int i = 0; i < 2; i++) { Console.WriteLine("Press Enter to release another thread."); Console.ReadLine(); event_1.Set(); Thread.Sleep(250); } Console.WriteLine("\r\nAll threads are now waiting on AutoResetEvent #2."); for (int i = 0; i < 3; i++) { Console.WriteLine("Press Enter to release a thread."); Console.ReadLine(); event_2.Set(); Thread.Sleep(250); } // Visual Studio: Uncomment the following line. //Console.Readline(); } static void ThreadProc() { string name = Thread.CurrentThread.Name; Console.WriteLine("{0} waits on AutoResetEvent #1.", name); event_1.WaitOne(); Console.WriteLine("{0} is released from AutoResetEvent #1.", name); Console.WriteLine("{0} waits on AutoResetEvent #2.", name); event_2.WaitOne(); Console.WriteLine("{0} is released from AutoResetEvent #2.", name); Console.WriteLine("{0} ends.", name); }}
View Code
8. ManualResetEvent manual reset event
public class Example{ // mre is used to block and release threads manually. It is // created in the unsignaled state. private static ManualResetEvent mre = new ManualResetEvent(false); static void Main() { Console.WriteLine("\nStart 3 named threads that block on a ManualResetEvent:\n"); for(int i = 0; i <= 2; i++) { Thread t = new Thread(ThreadProc); t.Name = "Thread_" + i; t.Start(); } Thread.Sleep(500); Console.WriteLine("\nWhen all three threads have started, press Enter to call Set()" + "\nto release all the threads.\n"); Console.ReadLine(); mre.Set(); Thread.Sleep(500); Console.WriteLine("\nWhen a ManualResetEvent is signaled, threads that call WaitOne()" + "\ndo not block. Press Enter to show this.\n"); Console.ReadLine(); for(int i = 3; i <= 4; i++) { Thread t = new Thread(ThreadProc); t.Name = "Thread_" + i; t.Start(); } Thread.Sleep(500); Console.WriteLine("\nPress Enter to call Reset(), so that threads once again block" + "\nwhen they call WaitOne().\n"); Console.ReadLine(); mre.Reset(); // Start a thread that waits on the ManualResetEvent. Thread t5 = new Thread(ThreadProc); t5.Name = "Thread_5"; t5.Start(); Thread.Sleep(500); Console.WriteLine("\nPress Enter to call Set() and conclude the demo."); Console.ReadLine(); mre.Set(); // If you run this example in Visual Studio, uncomment the following line: //Console.ReadLine(); } private static void ThreadProc() { string name = Thread.CurrentThread.Name; Console.WriteLine(name + " starts and calls mre.WaitOne()"); mre.WaitOne(); Console.WriteLine(name + " ends."); }}
View Code
9. In some collection classes, such as Queue, ArrayList, HashTable, and Stack,. NET already provides an object SyncRoot for lock.
Queue q = new Queue(); lock (q.SyncRoot) { foreach (object item in q) { //do something } }
View Code
References: http://blog.csdn.net/zzy7075/article/details/29842165