Under normal circumstances, as long as multi-threaded programming is involved, the complexity of the program will increase significantly, the performance will decrease significantly, and the probability of bugs will be greatly increased.
Multithreaded programming is intended to run a program in parallel to improve data processing capabilities, but in most cases, it involves competition for shared resources, so it must be locked when modifying resource objects. However, there are many ways to implement locks, so let's take a look at the implementation and performance of several types of locks in C#.
Several ways to use locks
1. Atomic lock
Achieve "lockless" competition through the atomic operation Interlocked.CompareExchange.
The official explanation is to provide atomic operations for variables shared by multiple threads. Namespace: System.Threading
2. Critical area
Serialization of multiple threads to access public resources or a piece of code is fast and suitable for controlling data access. The lock syntax in C# is a syntax sugar for the critical area (Monitor).
3. Atomic operation
Atomic operations, which are a special case, are inherently thread-safe, so there is no need to lock them.
Officially interpreted as incrementing the value of a given variable in the form of an atomic operation and storing the result. Namespace: System.Threading
4. Read and write lock
Read-write locks allow reading resources when other programs are writing, so if the resource allows dirty reads, this is more appropriate.
The official explanation indicates a locked state used to manage resource access, enabling multi-threaded reads or exclusive write access. The namespace is System.Threading
5. Semaphore
Semaphores, designed to control a limited number of user resources.
The official explanation limits the number of threads that can access a resource or resource pool at the same time. The namespace is System.Threading
6. Events
Used to notify the thread that some events have occurred, starting the start of a successor task.
The official explanation states that thread synchronization events automatically reset when a signal is received after a thread is released. Such types cannot be inherited.
7. Mutual exclusion
There is a Mutex class in C#, just under the System.Threading namespace, Mutex is actually a mutex, which can not only deal with resource competition between multiple threads, but also handle resource competition between processes.
Performance test code
Run the code
Performance test results
Note: The above data is only the result of the hardware performance of the current test environment, and can only be compared with each other.
1) In various tests, it is definitely the fastest to not lock, so try to avoid resource competition that leads to locked operation.
2) Interlocked.CompareExchange consistently shows superior performance in multi-threading, ranking second.
3) The third lock, the critical zone also shows good performance, so please refute others when they say that the lock performance is low.
4) The fourth place is atomic variable (Atomic) operation, but at present, it only supports the self-increase and subtraction of variables, and the applicability is not strong.
5) The performance of the fifth read/write lock (ReaderWriterLockSlim) is also okay, and it supports reading nothing, and the practicality is still relatively good.
6) The remaining semaphores, events, and mutex have the worst performance, of course, they have their own scope of application, but they do not perform well in dealing with resource competition.
Original link address:The hyperlink login is visible.
|