Sync
When multiple threads share some data, we need to use synchronous technology to ensure that only one thread accesses the shared state at a time. Note that synchronization issues are related to contention and deadlock.
Cases:
Static intIDX =0;Static voidAdd () { for(inti =0; I <50000; i++) {idx++; }}Static voidMain () {Const intSIZE = +; Task[] Arr=NewTask[size]; while(true) { for(inti =0; i < SIZE; i++) {Arr[i]=NewTask (ADD); Arr[i]. Start (); //Start Multiple threads } for(inti =0; i < SIZE; i++) {Arr[i]. Wait (); //wait for thread to finish} Console.WriteLine (IDX); Thread.Sleep ( -); IDX=0;//Reset data, run again }}
Results:
1717634
1652989
1444839
1272385
1558097
1297459
1968232
2000000
Obviously, not what we want, we expect the result to be 2000000 per run. This is because idx++ is not thread-safe, and its operations include getting a value from memory, incrementing the value by 1, and then saving it back into memory. These operations can be interrupted by the thread scheduler.
In this case, we need some synchronous methods to solve the problem.
- lock The keyword marks a statement block as a critical section by obtaining a mutex for a given object, executing the statement, and then releasing the lock. Call enter at the beginning of the block, and call exit at the end of the block. This If another thread tries to enter the locked code, it waits (that is, is blocked) until the object is freed. A thread that, when blocked, does not occupy cpu resources.
Static Object New Object (); Static void Add () { for (int050000; i++) { Lock (locker) idx+ +; }}
- The interlocked class is used to make a simple statement atomic session of a variable (the smallest execution unit is not interrupted halfway), providing a way to increment, decrement, exchange, and read values in a thread-safe manner.
For the above example, replace the idx++ with the interlocked.increment (ref IDX);
- The monitor class is the pure class that implements the lock mechanism, and the lock statement is parsed by the compiler to use the Monitor class.
Lock (obj) { //synchronized region for obj} is equivalent to Monitor.Enter (obj); Try { //synchornized region for obj}finally{ Monitor.Exit (obj)}
Use TryEnter to add timeout
1 Objectobj =New Object();2Task.run (() ={3 Lock(obj)4 {5Console.WriteLine ("Lock obj");6Thread.Sleep ( the);7 }8 });9 BOOLb = Monitor.TryEnter (obj, -);Ten if(b) One { A Try - { -Console.WriteLine ("Monitor Enter."); the } - finally - { - monitor.exit (obj); + } - } + Else A { atConsole.WriteLine ("Monitor enter false."); - } - -Console.readkey ();
In addition, monitor provides a wait method that frees the lock on the object and blocks the current thread until it acquires the lock again.
Provides a pulse method to notify the waiting queue of a change in the state of a thread-locked object; PulseAll notifies all waiting thread object state changes.
C # Multithreading series (vi)