Thread Synchronization Technology

Source: Internet
Author: User

Reference: https://getpocket.com/a/read/929454653

first, look at a race condition

The Sharedstate class is used to hold congratulations on the data between threads, there is a Member State, and different threads can share state.

    public class Sharedstate    {public        int state {get; set;}    }

The job class contains the Dothejob () method, which is the entry point for the newly task, implemented by code, incrementing the state of the Sharedstate class by 50,000 times, sharedstate initialized in the constructor of the class (This.sharedstate)

    public class Job    {        sharedstate sharedstate;        Public Job (sharedstate sharedstate)        {            this.sharedstate = sharedstate;        }        Private Object syncobj = new Object ();        public void Dothejob ()        {for            (int i = 0; i < 50000; i++)            {sharedstate.state + = 1;            }        }     }

In the main method, create a Sharedstate object and pass it to the constructor of the 20 task object, after starting all the tasks, the Main () method enters another loop, waits for 20 tasks to complete, writes the shared state value to the console, Because 50,000 loops were performed, there were 20 tasks, so the expected result was 1 000 000, but that was not the case.

 

    Class program    {        static void Main (string[] args)        {            int numtasks =;            var state = new Sharedstate ();            var tasks = new Task[numtasks];            for (int i = 0; i < Numtasks, i++)            {                Tasks[i] = Task.run (() = new Job (state). Dothejob ());            }            for (int i = 0; i < numtasks; i++)            {                tasks[i]. Wait ();            }            Console.WriteLine ("Summarized {0}", state. State);            Console.readkey ();        }    }

The result of the execution three times is:

Summarized 381758

Summarized 531860

Summarized 316794

Different machine execution results may be different, but to illustrate a problem, in the context of multi-threaded parallel execution, congratulations that the data may be modified by other threads, resulting in unintended results.

For example, a total of two threads T1 and T2, the two threads take the value of the state and give it 1,state initial values of 1, when the T1 and T2 from the state to take out the value of 1, the respective execution plus 1 operation will return the result, then we get the result is 2, not 3, Because the state value that one thread takes out is not the result of another thread's execution, it causes a result error.

Second, C # Technology for multiple thread synchronization

If you need to share data in a thread, you need to use synchronization technology, the techniques that C # can use for multithreaded synchronization are:

    1. Lock statement
    2. Interlocked class
    3. Monitor class
    4. SpinLock structure
    5. WaitHandle class
    6. Mutex class
    7. Semaphore class
    8. Event class
    9. Barrier class
    10. ReaderWriterLockSlim
1. Lock Statement

The object representation defined by the lock statement, which is to wait for the specified object's lock, to pass only the reference type. Locking the type only locks a copy, which makes little sense, and the C # compiler issues an error if the lock statement is used on the value type. After locking--only one thread is locked, the lock statement block can be run, and at the end of the lock statement block, the lock is unlocked and another thread waiting to be locked can get the lock block.

We try to use lock (this) and lock (obj) to lock.

The following modifications are made to the Dothejob:

        public void Dothejob ()        {            lock (this)            {for                (int i = 0; i < 50000; i++)                {                   sharedstate.state + = 1;                   }            }        

The result is still not up to our expected 100 000, where the lock detachment works with threads of the same instance, tasks
Each character in [] invokes a different instance, so they all can use the Dothejob method at the same time.

The following modifications are made to the Dothejob:

        Private Object syncobj = new Object ();        public void Dothejob ()        {            lock (syncobj)            {for                (int i = 0; i < 50000; i++)                {                   Sharedstate.state + = 1;}}        

The result of the operation is also incorrect. Lock (Syncobj) only causes dothejob () to be inaccessible to other threads, but other members of the instance can still be accessed.

This can be explained more clearly in the following example.

Lock (This)

    public class LockThis    {        private bool DeadLock = true;        public void deadlocked ()        {            lock (this)            {while                 (DeadLock)                {                    Console.WriteLine ("Omg! I am locked! ");                    Thread.Sleep (+);                }                Console.WriteLine ("Deadlocked () End");             }        }        public void Dontlockme ()        {            deadLock = false;        }        Public  static void Lockthismethod ()        {            LockThis LockThis = new LockThis ();            Task.Factory.StartNew (lockthis.deadlocked);            Thread.Sleep (the);            Lock (LockThis)            {                lockthis.dontlockme ();}}    }

This method can be called by calling Lockthis.lockthismethod in Main ().

Operation Result:

In the Lockthismethod method, start the task Lockthis.deadlocke

Task.Factory.StartNew (lockthis.deadlocked);

An attempt was made to unlock the deadlock by Lockthis.dontlockme after the task started 5s, but it did not succeed and lockthis.deadlocked was not stopped.

Even the non-synchronous method Dontlockme () cannot be invoked because lock (this) locks the entire instance in a deadlock, causing the outer layer to synchronize access to this instance.

Lock (Syncobj)

    public class LockObject    {        private bool DeadLock = true;        Private Object syncobj = new Object ();        public void deadlocked ()        {            lock (syncobj)            {while                (DeadLock)                {                    Console.WriteLine ("Omg! I am locked! ");                    Thread.Sleep (+);                }                Console.WriteLine ("Deadlocked () End.");            }        }        public void Dontlockme ()        {            deadLock = false;        }        public static void Lockobjectmethod ()        {            LockObject lockobject = new LockObject ();            Task.Factory.StartNew (lockobject.deadlocked);            Thread.Sleep (the);            Lock (LockObject)            {                lockobject.dontlockme ();}}    }

 

This method can be called by calling Lockobject.lockobjectmethod in Main ().

Operation Result:

In the Lockobjectmethod method, start the task Lockobject.deadlocke

Task.Factory.StartNew (lockobject.deadlocked);

The attempt task began 5s later through Lockthis.dontlockme to unlock the deadlock, succeeded

Because lock (syncobj) locks only the deadlocked () method in deadlock, the non-synchronous method Dontlockme can be called when the outer layer also accesses the instance synchronously.

Summary: Because objects of a class can also be used for external synchronous access (the above lock (LockThis) and lock (lockobject) simulate such access), and we cannot control such access in the class itself, we should use Lock (obj) as much as possible, You can have more precise control over the range that needs to be synchronized.

Lock (this) locks the entire instance

Lock (obj) locks only the code within the range.

Lock (Typeod (staticclass)) locks static members

To take a look at it, modifying the Sharedstate class is infeasible.

        public class Sharedstate        {            Private object syncobj = new Object ();            private int state=0;            public int State             {                get                {lock (syncobj) {return _state;}}                Set                {lock (syncobj) {state = value;}}}}        

The shared state control is synchronized directly, but the expected result is still not coming out.

Misunderstanding: The understanding of synchronization is wrong, between reading and writing, Syncobj is not locked, still wired can be obtained during this period value.

Solution to the problem:  

1. Put the lock in the right place and use the appropriate lock object

        public void Dothejob ()        {for                (int i = 0; i < 50000; i++)                {                    lock (sharedstate)                        { Sharedstate.state + = 1;}}        

2, modify the design of the Sharedstate class, as an atomic operation to provide an incremental way

    public class Sharedstate    {        private int state = 0;        Private Object syncRoot = new Object ();        public int State        {            get {return ' state;}        }        public int incrementstate ()        {            lock (syncRoot)            {                return ++state;    }}}

  

  

  

Thread Synchronization Technology

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.