With the development of hardware, SMP (symmetric multi-processor) has become very common. If the scheduling mechanism of the kernel can be preemptible, SMP and kernel preemption are two scenarios of multi-thread execution. When multiple threads access the data structure of the kernel at the same time, we need to serialize it.
Spin lock and mutex
The Code area used to access Shared resources is called the critical section. The spin lock and mutex (Mutual Exclusion) are two basic mechanisms to protect the kernel critical section.
The spin lock determines that only one thread enters the critical section at the same time. Other threads (Execution threads) that want to enter the critical area must keep spinning in the original place to know the spin lock released by the first thread. The following describes how to use the spinlock function.
# Include <Linux/spinlock. h>/* initialize */spinlock_t _ Lock = spin_lock_unlocked;/* Lock */spin_lock (& _ Lock ); /* critical code */* release lock */spin_unlock (& _ Lock );
The mutex is different from the spin lock. When waiting outside the critical section, it does not stop spinning, but changes the current thread to sleep. If it takes a long time to execute the critical section, the mutex is more suitable for spin locks, but it makes better use of the CPU, rather than where to turn for a long time.
So how can we choose between them?
1. If you need to sleep in the critical section, you can only use mutex because it is illegal to schedule, seize, and wait for the queue to sleep after obtaining the spin lock.
2. Since the mutex puts the current thread into sleep state in the face of competition, the spin lock can only be used in the interrupt handler.
The following describes how to use mutex.
# Include <Linux/mutex. h> static define_mutex (_ mutex); mutex_lock (& _ mutex);/* critical section */mutex_unlock (& _ mutex)
The following describes kernel concurrency protection in four cases.
1. process context, single CPU, non-preemptible Kernel
This is the simplest and requires no locks.
2. Process and interrupt context, single CPU, non-preemptible Kernel
In this case, when protecting the critical section, you only need to disable interruption. A single CPU and non-preemptible kernel determine that the process will not be switched. However, in the critical section, the process may be interrupted, so the interruption must be disabled, that is, the interruption status should be saved when the critical section is entered, after leaving the critical section, the service is interrupted.
3. Process and interrupt context, single CPU, preemptible Kernel
In this case, compared with 2, the kernel can be preemptible, so you need to lock the critical section to prohibit kernel preemption, And the interruption is still the same as 2.
4. Process and interrupt context, SMP, preemptible Kernel
It is now executed on the SMP machine, and your kernel is configured with config_smp and config_preempt. In the SMP system, when a spin lock is obtained, only the interruption of the current CPU is disabled, and then the process context and interrupt handler can be performed on different CPUs, therefore, non-local CPU interrupt processing functions need to wait for the process context code on the CPU to launch the critical section. In the interrupt context, you must use spin_lock and spin_unlock.
Atomic operation
Atomic operations are used to perform lightweight and only one operation, such as modifying the timer, adding value with conditions, and setting bit. Atomic operations are serialized, and lock processing is not allowed. The time for atomic operations depends on the architecture.
Read/write lock
A variant of the spin lock-the read/write lock. If each execution unit either reads or writes data structures when accessing the critical section, but they do not perform read/write operations at the same time, the read/write lock is suitable. The read/write lock allows multiple threads to enter the critical section at the same time. However, if a write thread enters the critical section, other read/write processes must wait. Read/write lock usage:
Rwlock_t _ rwlock = unlock; read_lock (& _ rwlock);/* critical code */read_unlock (& _ rwlock); optional rwlock_t _ rwlock = unlock; wirte_lock (& _ rwlock ); /* critical code */wirte_unlock (& _ rwlock );