. NET advanced 06 async asynchronous, thread multithreading 4

. NET advanced 06 async asynchronous, thread multithreading 4
Knowledge needs to be accumulated, summarized and precipitated. Thinking and writing are the catalysts for growth

1, Lock

1,lock

2,Interlocked

3,Monitor

4,SpinLock

5,Mutex

6,Semaphore

7,Events

1,AutoResetEvent

2,ManualResetEvent

3,ManualResetEventSlim

8,ReaderWriterLock

2, Thread safe collection

3, Multithreading model

1. Synchronous programming model SPM

2. Asynchronous programming model APM

3. EAP based on event programming model

4. Task based programming model TAP

4, End

1, Lock
There are also lock concepts in the database, such as row lock, table lock, transaction lock, etc. the function of lock is to control the safety and consistency of data in the case of concurrency, so that when one data is operated, other concurrent threads wait. In terms of development, when multithreading parallel programming accesses shared data, in order to ensure the consistent security of data, it is sometimes necessary to use locks to lock objects to achieve synchronization

There are many thread synchronization technologies available in. NET.
Lock, Interlocked and Monitor are used for in-process synchronization lock,
Mutex mutex lock, Semaphore semaphore, Events, ReaderWriterLockSlim read / write lock, etc. are used for thread synchronization between multiple processes

1,lock
Lock statement is a simple way to set and unlock a pair, and it is also the most commonly used synchronization method. Lock is used to lock a reference type field. When a thread executes to lock, it will lock the field so that only one thread enters the lock statement block, and then the lock will be released at the end of the lock statement, and another thread can enter. The principle uses synchronous block index. If you are interested, you can study it

lock (obj)
{
    //synchronized region
}

Because only one thread can enter without concurrency, performance is sacrificed, so the scope of lock should be minimized. Another suggestion is to lock a private variable, that is, syncroot mode, and declare a private object variable of syncroot for locking instead of using lock(this), because external callers may also lock the instance of your object, But he doesn't know that you also use locks internally, so it's easy to cause deadlock

private object syscRoot = new object();
public void DoThis()
{
    lock (syscRoot)
    {
        //Only one thread can get here at a time
    }
}

2,Interlocked
Interloaded is used to atomize some simple operations of variables, that is, thread safe synchronization. i + + we often write is not thread safe. Take value from memory and then + 1 and put it back into memory. The process is likely to be interrupted by other threads. For example, when you put it back into memory after + 1, another thread has been put back first and is out of sync. The InerLocked class provides methods for incrementing, decrementing, exchanging, and reading values in a thread safe manner
For example, the following incremental method instead of lock

int num = 0;
//lock (syscRoot)
//{
//    num++;
//}
num = Interlocked.Increment(ref num);

3,Monitor
The above lock is the syntax sugar of Monitor. The compiler will generate Monitor code, like the following

lock (syscRoot)
{
    //synchronized region
}
//The lock lock above is equivalent to the Monitor below
Monitor.Enter(syscRoot);
try
{
    //synchronized region
}
finally
{
    Monitor.Exit(syscRoot);
}

Monitor is different from Lock in that it can also set the timeout time and will not wait indefinitely.

bool lockTaken = false;
Monitor.TryEnter(syscRoot,500,ref lockTaken);
if (lockTaken)
{
    try
    {
        //synchronized region
    }
    finally
    {
        Monitor.Exit(syscRoot);
    }
}
else
{
}

4,SpinLock
SpinLock spin lock is a user mode lock. By the way, the plug-in lock is divided into kernel mode lock and user mode lock. Kernel mode is to interrupt the thread at the system level and switch back to continue working when receiving the signal. User mode is to let the thread run until it is available through some CPU specified or dead loop. Each has its own advantages and disadvantages. The CPU resource utilization of the kernel is high, but the switching loss is opposite to the user mode. If the locking time is long, it will wait in vain, and then there will be a mixed mode lock

SpinLock is useful if there are a large number of locks and the locking time is very short. The usage is similar to that of Monitor. Enter or TryEnter obtains the lock and Exit releases the lock. IsHeld and IsHeldByCurrentThread specify whether it is currently locked

In addition, SpinLock is a structure type, so pay attention to the problem that a new copy will be created during copy assignment. Pass by reference if necessary

5,Mutex
Mutex mutex provides synchronization of a class across multiple processes. When defining a mutex, you can specify the name of the mutex so that the system can recognize it. Therefore, mutex defined in another process can also be accessed by other processes. Mutex Openexisting().

bool createdNew = false;
Mutex mutex = new Mutex(false, "ProCharpMutex", out createdNew);
if (mutex.WaitOne())
{
    try
    {
        //synchronized region
    }
    finally
    {
        mutex.ReleaseMutex();
    }
}

In this case, we can prohibit an application from starting twice. Generally, we judge it by the name of the process. Here we use Mutex to implement it

bool createdNew = false;
Mutex mutex = new Mutex(false, "SingletonWinAppMutex", out createdNew);
if (!createdNew)
{
    MessageBox.Show("The application has already started");
    Application.Exit();
    return;
}

6,Semaphore
Semaphore semaphore is similar to mutex. The difference is that semaphore can be used by multiple threads at the same time. It is a counting mutex lock. Counting allows several threads to access protected resources at the same time. You can also specify a semaphore name to be shared among multiple processes

Semaphore and Mutex above inherit from the WaitHandle base class. WaitHandle is used to Wait for a signal setting. If Wait is used, the thread will Wait to receive a signal related to the waiting handle

SemaphoreSlim is a lightweight alternative version of Semaphore (it does not inherit the WaitHandle). The SemaphoreSlim(int initialCount, int maxCount) constructor can specify the maximum number of concurrency, and then Wait in the thread through SemaphoreSlim's Wait until it receives whether the signal can enter the protected code block. Finally, remember to Release, Otherwise, the next thread cannot get the signal of permission to enter

7,Events
The Events event lock is different from the Events in the delegate. In system The threading namespace is used to synchronize event resources within the system.

have AutoResetEvent Automatic event lock
ManualResetEvent Manual event lock
 And lightweight versions ManualResetEventSlim

1,AutoResetEvent
AutoResetEvent also inherits from the waitHandle class and waits through WaitOne until there is a signal,
It has two states: terminated and non terminated. You can call the set and reset methods to make the object enter the terminated and non terminated states.
The popular point is that if there is a signal in set, another thread can enter. If reset is not terminated and has no information, other threads will be blocked.
Automatic means that when a thread enters, the automatic Reset setting has no signal, and other threads cannot enter.
Similar to the real car toll gate, one shot one car mode.

private AutoResetEvent autoEvent = new AutoResetEvent(false);
public void DoThis()
{
    autoEvent.WaitOne();
    //Execute synchronous code block
    autoEvent.Set();
}

2,ManualResetEvent
The difference between manual event lock and automatic event lock is that when there is no signal, a group of threads will be blocked. When there is a signal, all threads will run and wake up multiple threads at the same time, unless it is blocked again by manual Reset. Similar to the fence at the intersection of Railway track in the real scene, a group of people will be intercepted when the rod falls, and a group of people will rush through when the rod rises. The usage is the same as above. WaitOne waits for the signal, At the end, use Set to notify that there is a signal and it can pass

3,ManualResetEventSlim
ManualResetEventSlim provides a mixed lock mode of spin Wait and kernel Wait by encapsulating ManualResetEvent. If cross process or cross AppDomain synchronization is required, manual resetevent must be used. ManualResetEventSlim uses Wait to block threads and supports task cancellation. Like SemaphoreSlim's Wait, it is more efficient to spin internally through user mode and then through kernel mode.

8,ReaderWriterLock
The ReaderWriterLock read-write lock protects resources not from the perspective of limiting the number of threads, but from the perspective of reading and writing. That is, you can lock that when one of a kind of thread (write thread) enters the protected resources, the other kind of thread (read thread) is blocked. If no write thread locks the resource, multiple read thread method resources are allowed, but only one write thread can lock the resource

Refer to examples for specific usage

//Create read / write lock

ReaderWriterLock rwLock = new ReaderWriterLock();
// The current thread obtains the read lock. The parameters are: timeout value (MS)
rwLock.AcquireReaderLock(250);
// Judge whether the current thread holds a read lock
if (!rwLock.IsReaderLockHeld)
{
    return;
}
Console.WriteLine("Got the read lock......");
// Upgrade the read lock to write lock. The lock parameters are: timeout value (MS)
LockCookie cookie = rwLock.UpgradeToWriterLock(250);
// Determine whether the current thread holds a write lock
if (rwLock.IsWriterLockHeld)
{
    Console.WriteLine("Upgraded to write lock......");
    // Restore the lock to the previous level, that is, read the lock
    rwLock.DowngradeFromWriterLock(ref cookie);
}
// Release the read lock (reduce the lock count until the lock is released when the count reaches zero)
rwLock.ReleaseReaderLock();
Console.WriteLine("Successful implementation completed......");

// The current thread obtains the write lock. The parameters are: timeout value (MS)
rwLock.AcquireWriterLock(250);
// Determine whether the current thread holds a write lock
if (rwLock.IsWriterLockHeld)
{
    Console.WriteLine("Got the write lock......");
    // Release the write lock (the write lock count will be reduced until the count becomes zero and the lock will be released)
    rwLock.ReleaseWriterLock();
}
// Release the write lock (the write lock count will be reduced until the count becomes zero and the lock will be released)
// If the current thread does not hold a lock, an exception will be thrown
rwLock.ReleaseWriterLock();
Console.WriteLine("Successful implementation completed......");
Console.ReadLine();

ReaderWriterLockSlim is also a lightweight optimized version of ReaderWriterLock, which simplifies the rules of recursion, upgrading and demoting locking states.

  1. EnterWriteLock enters write mode lock state
  2. EnterReadLock enters the read mode lock state
  3. EnterUpgradeableReadLock enters an upgradeable read mode lock state
    In addition, the three locking modes have a timeout mechanism and a corresponding Try... Method. When exiting the corresponding mode, the Exit... Method is used, and all methods must appear in pairs

2, Thread safe collection
In order to ensure resource security, the lock or semaphore described above is usually used to solve this problem. Actually NET also has built-in thread safe collections. Using them is like using single threaded collections.

Type description

BlockingCollection provides any type of restriction and blocking function for implementing IProducerConsumerCollection.
For more information, see BlockingCollection overview. ConcurrentDictionary<tkey,tvalue
style="font-size: inherit; color: inherit; line-height: inherit;
margin: 0px; padding: 0px;”> Thread safe implementation of key / value pair dictionary.
Thread safe implementation of ConcurrentQueue FIFO queue.
Thread safe implementation of ConcurrentStack LIFO stack. ConcurrentBag is a thread safe implementation of an unordered collection of elements.
The IProducerConsumerCollection type must implement an interface for use in BlockingCollection.

3, Multithreading model
1. Synchronous programming model SPM
2. Asynchronous programming model APM
The two classic pairing methods, XXBegin and XXEnd, are asynchronous. After Begin, it will be delegated to the thread pool to call a thread for execution. And the BeginInvoke call of the delegate

FileStream fs = new FileStream("D:\\test.txt", FileMode.Open);
var bytes = new byte[fs.Length];
fs.BeginRead(bytes, 0, bytes.Length, (aysc) =>
{
    var num = fs.EndRead(aysc);
}, string.Empty);

3. EAP based on event programming model
BackgroundWorker class in WinFrom/WPF development is an implementation scheme of asynchronous event mode. RunWorkerAsync method starts the method asynchronously associated with DoWork event. After the work is completed, RunWorkerCompleted event will be triggered. It also supports CancelAysnc method cancellation and ReportProgress notification. Another typical example is WebClient

WebClient client = new WebClient();
client.DownloadDataCompleted += (sender,e)=> 
{
};
client.DownloadDataAsync(new Uri("https://www.baidu.com/"));

4. Task based programming model TAP
After the Task came out, Microsoft vigorously promoted the asynchronous programming model based on Task, and APM and EAP were packaged as tasks. The following example simply encapsulates the above programming model with Task. The DownloadDataTaskAsync implementation of WebClient is similar to that in the example, which is wrapped into a Task using a TaskCompletionSource wrapper

FileStream fs = new FileStream("D:\\test.txt", FileMode.Open);
var bytes = new byte[fs.Length];
var task = Task.Factory.FromAsync(fs.BeginRead, fs.EndRead, bytes, 0, bytes.Length, string.Empty);
var nums = task.Result;

Action action = () =>{ };
var task = Task.Factory.FromAsync(action.BeginInvoke, action.EndInvoke, string.Empty);

public static Task<int> GetTaskAsuc(string url)
{
    TaskCompletionSource<int> source = new TaskCompletionSource<int>();//Wrapper
    WebClient client = new WebClient();
    client.DownloadDataCompleted += (sender, e) =>
    {
        try
        {
            source.TrySetResult(e.Result.Length);
        }
        catch (Exception ex)
        {
            source.TrySetException(ex);
        }
    };
    client.DownloadDataAsync(new Uri(url));
    return source.Task;
}

4, End
Recent articles have introduced how to write multithreaded and multitasking applications. In the process of application development, we should plan carefully. Too many threads lead to resource problems, and too few threads can not achieve great results. A pertinent suggestion in multithreaded programming is
Try to avoid modifying shared variables to reduce the requirement of synchronization. Through reasonable planning, most of the synchronization complexity can be reduced.

Search the fucking web
Read the fucking maunal

-GoodGoodStudy

Keywords: Java .NET microsoft

Added by syacoub on Wed, 16 Feb 2022 01:52:54 +0200