C # thread synchronization

Source: Internet
Author: User
Tags exit in

Citation: http://www.cnblogs.com/michaelxu/archive/2008/09/20/1293716.html

First, the volatile keyword

Volatile is the simplest method of synchronization, and of course, it's a price to pay. It can only be synchronized at the variable level, the meaning of volatile is to tell the processor, do not put me into the working memory, please directly in main memory operation me. ("www.bitsCN.com") therefore, when multithreading accesses the variable at the same time, it will manipulate the main memory directly and do the variable sharing in essence.

usingSystem;namespaceconsoleapplication1{classProgram {Private Static volatile int_i;  Public Static intI {Get{return_i;} Set{_i =value;} }        Static voidMain (string[] args)        {Console.WriteLine (_i); }    }}

However, volatile does not achieve true synchronization because its operating level is only at the variable level, not at the atomic level. If it is in a single processor system, there is no problem, the variable in main memory has no chance to be modified by others, because there is only one processor, which is called Processor self-consistency. However, in a multiprocessor system, there may be a problem. Each processor has its own data cach, and the updated data is not necessarily immediately written back to main memory. So it can be a different step, but it's very difficult to happen because the Cach read and write very fast, flush frequency is also very high, only when the stress test can occur, and the probability is very very small.

Second, lock keyword

Lock is a simple and easy way to synchronize threads by acquiring mutexes for a given object. It ensures that when a thread is in a critical section of code, another thread does not come in, it waits until the thread object is freed, that is, the thread is out of the critical section. Usage:

 using   System;  namespace   consoleapplication1{ class   program { static  void  Main (string  [] args) { object LockThis = new  ();  lock   (LockThis) {//  Access thread-sensitive resources.   

The parameter of lock must be based on the reference type of the object, not the basic type like bool,int, so it is not synchronous at all, because the parameters of lock is the object, if the incoming int, it is bound to take place boxing operation, so each lock will be a new different object. It is best to avoid using the public type or an object instance that is not controlled by the program because it is likely to cause deadlocks. In particular, do not use a string as a parameter to lock because the string is "persisted" by the CLR, meaning that there is only one instance of the string given in the entire application, so it is more likely to cause deadlocks. It is recommended that you use a private or protected member that is not "persisted" as a parameter. In fact, some classes have already provided dedicated members to be locked, such as the array type provides SyncRoot, and many other collection types also provide syncroot.

Therefore, use lock should pay attention to the following points:

1, if the instance of a class is public, it is best not to lock (this). Because the person who uses your class may not know that you are using lock, and if he has a new instance, and locks the instance, it can easily cause a deadlock.

2, if the MyType is public, do not lock (typeof (MyType))

3. Never lock a string

  Third, System.Threading.Interlocked

For simple operations of integer data types, you can use the members of the Interlocked class to implement thread synchronization, which exists in the System.Threading namespace. The Interlocked class has the following methods: Increment, Decrement, Exchange, and CompareExchange. Using increment and decrement guarantees that an integer can be added and reduced to an atomic operation. The Exchange method automatically swaps the value of the specified variable. The CompareExchange method combines two actions: comparing two values and storing the third value in one of the variables based on the result of the comparison. The comparison and interchange operations are also performed by atomic operations. Such as:

usingSystem;namespaceconsoleapplication1{classProgram {Static voidMain (string[] args) {            inti =0; System.Threading.Interlocked.Increment (refi);            Console.WriteLine (i); System.Threading.Interlocked.Decrement (refi);            Console.WriteLine (i); System.Threading.Interlocked.Exchange (refI -);            Console.WriteLine (i); System.Threading.Interlocked.CompareExchange (refITen, -);        Console.WriteLine (i); }    }}

Output:

Iv. Monitor

The Monitor class provides functionality similar to lock, but unlike lock, it has better control over the synchronization block, and when the Enter (object o) method of Monitor is called, the exclusive right of O is obtained until the exit (object O) method is called. To release exclusive rights to O, you can call the Enter (object o) method multiple times, just call the same number of exit (object O) methods, and the Monitor class provides an overloaded method of TryEnter (object O,[int]). This method attempts to acquire the exclusive rights of an O object, and returns false when the acquisition of exclusive rights fails.

However, using lock is generally preferable to using Monitor directly, on the one hand because lock is more concise and, on the other hand, because lock ensures that even protected code throws an exception, You can also release the base monitor. This is done by calling exit in finally . In fact,lock is implemented using the Monitor class.

For usage, refer to the following code:

usingSystem;usingSystem.Threading;namespaceconsoleapplication1{classProgram {Private Static ObjectM_monitorobject =New Object(); [STAThread]Static voidMain (string[] args) {Thread Thread=NewThread (NewThreadStart (DO)); Thread. Name="Thread1"; Thread thread2=NewThread (NewThreadStart (DO)); Thread2. Name="Thread2"; Thread.            Start (); Thread2.            Start (); Thread.            Join (); Thread2.            Join ();        Console.read (); }        Static voidDo () {if(!Monitor.TryEnter (M_monitorobject)) {Console.WriteLine ("Can ' t visit Object"+Thread.CurrentThread.Name); return; }            Try{monitor.enter (m_monitorobject); Console.WriteLine ("Enter Monitor"+Thread.CurrentThread.Name); Thread.Sleep ( the); }            finally{monitor.exit (m_monitorobject); }        }    }}

When thread 1 acquires the M_monitorobject object exclusive, thread 2 attempts to call TryEnter (M_monitorobject), which returns false due to the inability to acquire exclusive rights, with the following output information:

In addition, Monitor provides three static methods Monitor.pulse (Object o), Monitor.pulseall (object o) and Monitor.Wait (Object o), which are used to implement a wake-up mechanism for synchronization. For the use of these three methods, you can refer to MSDN, which is not detailed here.

  V. mutexes

In use, the mutex is closer to the above monitor, but the mutex does not have the Wait,pulse,pulseall function, so we cannot use the mutex to implement a similar wake-up function. However, mutexes have a relatively large feature, and mutexes are cross-process, so we can use the same mutex on multiple processes on the same machine or even a remote machine. Although the mutex can also implement in-process thread synchronization and is more powerful, it is recommended to use monitor in this case, because the mutex class is Win32 encapsulated, so it requires an interoperability transformation that consumes more resources.

  Liu, ReaderWriterLock

In the case of resource access, we implement the lock mechanism on the resource, but in some cases we just need to read the data of the resource, rather than modify the data of the resource, and in such cases the exclusive right to get the resource will undoubtedly affect the operational efficiency, therefore. NET provides a mechanism for resource access using ReaderWriterLock, if a resource does not acquire write exclusive rights at a time, then multiple read access rights can be obtained, exclusive rights for a single write, and if the exclusive right to write has been acquired at a moment, Then the other read access must wait, referring to the following code:

usingSystem;usingSystem.Threading;namespaceconsoleapplication1{classProgram {Private StaticReaderWriterLock M_readerwriterlock =NewReaderWriterLock (); Private Static intM_int =0; [STAThread]Static voidMain (string[] args) {Thread Readthread=NewThread (NewThreadStart (Read)); Readthread.name="ReadThread1"; Thread readThread2=NewThread (NewThreadStart (Read)); Readthread2.name="ReadThread2"; Thread Writethread=NewThread (NewThreadStart (Writer)); Writethread.name="Writerthread";            Readthread.start ();            Readthread2.start ();            Writethread.start ();            Readthread.join ();            Readthread2.join ();            Writethread.join ();         Console.ReadLine (); }        Private Static voidRead () { while(true) {Console.WriteLine ("ThreadName"+ Thread.CurrentThread.Name +"AcquireReaderLock"); M_readerwriterlock.acquirereaderlock (10000); Console.WriteLine (String.Format ("ThreadName: {0} m_int: {1}", Thread.CurrentThread.Name, M_int));            M_readerwriterlock.releasereaderlock (); }        }        Private Static voidWriter () { while(true) {Console.WriteLine ("ThreadName"+ Thread.CurrentThread.Name +"AcquireWriterLock"); M_readerwriterlock.acquirewriterlock ( +); Interlocked.Increment (refm_int); Thread.Sleep ( the);                M_readerwriterlock.releasewriterlock (); Console.WriteLine ("ThreadName"+ Thread.CurrentThread.Name +"Releasewriterlock"); }        }    }}

In the program, we start two threads to get read access to the M_int, use a thread to get the write exclusive rights of the M_int, and after executing the code, the output is as follows:

As you can see, any other read thread must wait until Writerthread acquires the write exclusive rights, until Writerthread releases the write exclusive to gain access to the data, it should be noted that the above printing information clearly shows that It is possible for multiple threads to fetch the data at the same time, as can be seen from the output of the ReadThread1 and ReadThread2 information interactions.

  Seven, SynchronizationAttribute

When we determine that an instance of a class can only be accessed by one thread at a time, we can directly identify the class as synchronization, so that the CLR automatically implements the synchronization mechanism for this class, which in fact involves the concept of a synchronous domain, when the class is designed as follows We can ensure that an instance of a class cannot be accessed concurrently by multiple threads
1). In the declaration of the class, add the System.Runtime.Remoting.Contexts.SynchronizationAttribute property.
2). Inherit to System.ContextBoundObject
It should be noted that to implement the above mechanism, the class must inherit to System.ContextBoundObject, in other words, the class must be context bound.
A demonstration class code is as follows:

namespace consoleapplication1{    [System.Runtime.Remoting.Contexts.Synchronization]    class  SynchronizedClass:System.ContextBoundObject    {    }}

Eight,MethodImplAttribute

If the critical section spans the entire method, that is, the code inside the entire method needs to be locked, it is easier to use the MethodImplAttribute property. So you don't have to lock inside the method, just add [MethodImpl (methodimploptions.synchronized)] on the method, Both Mehthodimpl and methodimploptions are inside the namespace System.Runtime.CompilerServices. Note, however, that this property locks the entire method until the method returns, releasing the lock. Therefore, the use is not very flexible. If you want to release the lock early, you should use monitor or lock. Let's look at an example:

C # thread synchronization

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.