This article from: http://blog.163.com/hbu_lijian/blog/static/126129153201261722410353/
Kernel synchronization measures (for Linux kernel)
To avoid concurrency and prevent competition. The kernel provides a set of Synchronization Methods to protect shared data. Our focus is not to introduce the detailed usage of these methods, but to emphasize the difference between these methods and them.
The synchronization mechanism used in Linux has been continuously improved since 2.0 to 2.6. From the initial atomic operation to the subsequent semaphores, from the large kernel lock to today's spin lock. The development of these synchronization mechanisms is accompanied by the overprovisioning of Linux from a single processor to a symmetric multi-processor, and the overprovisioning of a non-preemptible kernel to a preemptible kernel. The locking mechanism becomes more effective and more complex.
Currently, sub-operations in the kernel are mostly used for counting. In other cases, two locks and their variants are most commonly used: one is the spin lock and the other is the semaphore. We will introduce the two lock mechanisms below.
Spin lock
------------------------------------------------------
The spin lock is a kind of lock introduced to prevent multi-processor concurrency. It is widely applied to interrupt processing and other parts in the kernel (for single processor, to prevent the concurrency in the interrupt processing, you can simply disable the interrupt without the need to spin the lock ).
A spin lock can only be held by one kernel task at most. If a kernel task attempts to request a spin lock that has been used (held, then this task will always be busy loop-rotate-Wait for the lock to be available again. If the lock is not in contention, the kernel task requesting it will immediately get it and continue. The spin lock can prevent more than one kernel task from entering the critical section at any time. Therefore, this lock can effectively avoid competition for shared resources for Kernel Tasks running concurrently on the multi-processor.
In fact, the intention of the spin lock is to implement lightweight locking in a short period of time. A competing spin lock allows the thread requesting it to spin while waiting for the lock to be available again (especially wasting processing time), so the spin lock should not be held for too long. If you need to lock for a long time, it is best to use a semaphore.
The basic form of the spin lock is as follows:
Spin_lock (& mr_lock );
// Critical section
Spin_unlock (& mr_lock );
Because the spin lock can only be held by up to one kernel task at a time point, only one thread is allowed to exist in the critical section at a time point. This satisfies the locking service required by Symmetric Multi-processing machines. On a single processor, the spin lock is only used as a switch to set kernel preemption. If the kernel preemptible does not exist, the spin lock will be completely removed from the kernel during compilation.
To put it simply, spin locks are mainly used in the kernel to prevent concurrent access to the critical zone in the multi-processor and to prevent competition caused by kernel preemption. In addition, the spin lock does not allow the task to sleep (sleep of a task holding the spin lock will cause an automatic deadlock-Because sleep may cause the kernel task holding the lock to be rescheduled, apply for a lock that you already hold), which can be used in the interrupt context.
Deadlock: Assume one or more kernel tasks and one or more resources. Each kernel is waiting for one of these resources, but all resources are occupied. In this case, all kernel tasks are waiting for each other, but they will never release the occupied resources. Therefore, no kernel task can obtain the required resources and continue running, this means that the deadlock has occurred. Self-occupation means that you possess a certain resource, and then apply for the resource that you already possess. Obviously, it is impossible to obtain the resource again.
Semaphores
------------------------------------------------------
Semaphores in Linux are sleep locks. If a task tries to obtain an held semaphore, the semaphore will push it into the waiting queue and then sleep it. In this case, the processor is free to execute other code. When the process holding the semaphore releases the semaphore, a task in the waiting queue will be awakened to obtain the semaphore.
The sleep feature of semaphores makes the semaphores suitable for cases where the lock is held for a long time. They can only be used in the process context because the interrupt context cannot be scheduled; in addition, when the Code holds a semaphore, it cannot hold a spin lock.
The basic usage of semaphores is as follows:
Static declare_mutex (mr_sem); // declare mutex semaphores
If (down_interruptible (& mr_sem ))
// Interrupted sleep. When the signal arrives, the sleep task is awakened.
// Critical section
Up (& mr_sem );
Differences between semaphores and spin locks
------------------------------------------------------
Although the conditions for use between the two are complex, in fact, in actual use, semaphores and spin locks are not easy to confuse. Note the following principles:
If the code needs to sleep-this often happens when it is synchronized with the user space-using semaphores is the only option. Because it is not restricted by sleep, it is generally easier to use semaphores. If you need to choose between the spin lock and semaphore, it depends on the length of time the lock was held. Ideally, all locks should be held as short as possible, but it is better to use semaphores if they are held for a long time. In addition, unlike the spin lock, semaphores do not disable kernel preemption, so the code holding semaphores can be preemptible. This means that the semaphore will not have a negative impact on the scheduling response time.
Atomic operation:
The so-called atomic operation means that the operation will never be interrupted by any other task or event before execution is completed. That is to say, its smallest execution unit cannot have a smaller execution unit than it, so here the atom actually uses the concept of material particles in physics.
Atomic operations require hardware support, so they are architecture-related. Their APIs and atomic types are defined in the kernel source code tree include/ASM/atomic. in the H file, they are all implemented in assembly language, because the C language cannot implement such operations.
Atomic operations are usually used to implement reference counting of resources. In the IP Fragment processing of the TCP/IP protocol stack, reference counting is used, and the fragmentation queue structure struct ipq describes an IP fragment, the refcnt field refers to the reference counter. Its type is atomic_t. When an IP fragment is created (in the ip_frag_create function), use the atomic_set function to set it to 1. When the IP fragment is referenced, use the atomic_inc function to add 1 to the reference count.
Spin lock and mutex lock:
The spin lock is similar to the mutex lock, but the spin lock does not cause the caller to sleep. If the spin lock has been maintained by other execution units, the caller always loops there to see if the lock owner has released the lock. Therefore, the word "Spin" is named. It is used to solve the mutual exclusion of a resource. Because spin locks do not cause callers to sleep, the efficiency of spin locks is much higher than that of mutex locks. Although it is more efficient than mutex lock, it also has some shortcomings:
1. The spin lock occupies the CPU all the time, and runs until the lock is obtained. So it occupies the CPU. If the lock cannot be obtained within a short period of time, this will undoubtedly reduce the CPU efficiency.
2. A deadlock may occur when a spin lock is used, and a deadlock may occur when a recursive call is made. calling other functions may also lead to deadlocks, such as copy_to_user (), copy_from_user (), and kmalloc ().
The mutex is mainly used to implement the mutex access function in the kernel. Kernel mutex is implemented on the atomic API, but this is invisible to kernel users. Access to it must follow some rules: Only one task can hold a mutex lock at a time, and only this task can unlock the mutex lock. The mutex lock cannot be recursively locked or unlocked. An exclusive lock object must be initialized through its API, instead of using memset or replication for initialization. A task cannot end when it holds a mutex lock. The memory used by the mutex cannot be released. Mutex lock in use cannot be reinitialized. The mutex cannot be used to interrupt the context. However, mutex locks are faster and more compact than the current kernel semaphore options, so if they meet your needs, they will be your wise choice.
Semaphores
------------------------------------------------------
Recommended locking method
The spin lock is preferred for low-cost locking.
Short-term locks give priority to spin locks
Semaphores are preferentially used for long-term locking.
Apply spin lock to intercept context locking
Holding locks requires sleep and scheduling to use semaphores.