Linux semaphore and mutex for concurrency control of Linux device driver

Semaphore and Mutex

  • In the Linux device driver code, in order to solve the race condition, the way is to ensure exclusive access to shared resources; the so-called exclusive access means that when one execution unit accesses the shared resource, other execution units are prohibited from accessing.
  • The code area that accesses shared resources is called the critical section, and the critical section needs to be protected by a mutual exclusion mechanism. Interrupt shielding, atomic operations, spin locks, semaphores, mutexes, etc. are mutually exclusive approaches that can be used in Linux device drivers.

signal

Semaphore is the most typical means for synchronization and mutual exclusion in the operating system. The value of the semaphore can be 0, 1, or n. The semaphore corresponds to the PV operation in the operating system.

  • P(S)
    (1) Decrease the value of semaphore S by 1, that is, S = S-1;
    (2) If S >= 0, the process continues to execute; otherwise, the process is set to a waiting state and enters the waiting queue .
  • V(S)
    (1) Increase the value of the semaphore S by 1, that is, S = S + 1;
    (2) If S> 0, wake up the process waiting for the semaphore in the queue.

The related operations on Linux semaphores are as follows:

Define semaphore

struct semaphore sem; //定义名称为sem的信号量

Initialize the semaphore

void sema_init(struct semaphore *sem,int val); //该函数用于初始化信号量,并将信号量sem的值设置为val

Get semaphore

void down(struct semaphore *sem);  //获得信号量,会导致睡眠,因此不能在中断上下文中使用
int down_interruptible(struct semaphore *sem); 
//功能与down函数类似,但是down()进入状态的进程不能被信号打断
//down_interruptible()进入睡眠状态的进程能被信号打断,信号也会导致该函数返回,这是函数返回值非0
int down_trylock(struct semaphore *sem); 
//尝试获取信号量sem,如果能够立即获得,它就获得该信号量并返回0,否则,返回非0值。
//它不会导致调用者睡眠,可以在中断上下文中使用

Note: When using the down_interruptible() function to obtain the semaphore, the return value is generally checked. If it is not 0, it usually returns -ERESTARTSYS immediately, as follows:

if( down_interruptible(&sem) )
	return -ERESTARTSYS;

Release semaphore

void up(struct semaphore *sem);  //释放信号量sem,唤醒等待者

As a possible means of mutual exclusion, semaphores can protect critical sections, and its use is similar to spin locks. As with the spin lock, only the process that gets the semaphore can execute the critical section code. However, unlike the spin lock, when the semaphore cannot be obtained, the process will not spin in place but enter a sleep waiting state. When used as mutual exclusion, semaphores are generally used as follows:
Insert picture description here
in the new Linux kernel, they tend to directly use mutex (mutual exclusion) as a means of mutual exclusion, and semaphores are no longer recommended for mutual exclusion.

Semaphore synchronization

Semaphores can also be used for synchronization. One process A executes down() to wait for the semaphore, and another process B executes up() to release the semaphore, so that process A waits for process B synchronously. The process is similar:
Insert picture description here
For producer/consumer issues that care about specific values, semaphores are more appropriate. Because the producer/consumer problem is also a synchronization problem.

Mutex

Mutex (mutex) exists in the Linux kernel.
The following code defines the mutex and initializes it:

struct mutex my_mutex; //定义互斥体mutex
mutex_init(&my_mutex); //初始化互斥体mutex

The following code is used to obtain the mutex:

void mutex_lock(struct mutex *lock); //获取互斥体,进入等待状态,不能被信号打断
int mutex_lock_interruptible(struct mutex *lock); //获取互斥体,进入等待状态,但是可以被信号打断
int mutex_trylock(struct mutex *lock); //用于尝试获取互斥体mutex,获取不到mutex时不会引起进程睡眠

The following code is used to release the mutex:

void mutex_unlock(struct mutex *lock);  //释放互斥体

The method of using mutex is exactly the same as when semaphore is used for mutual exclusion, as follows:

struct mutex my_mutex; //定义mutex
mutex_init(&my_mutex); //初始化mutex
mutex_lock(&my_mutex); //获取mutex
... //临界资源
mutex_unlock(&my_mutex); //释放mutex

Spin lock and mutex use choice

  • Mutex and spinlock belong to different levels of mutual exclusion, and the realization of the former depends on the latter. In the realization of the mutex itself, in order to ensure the atomicity of access to the mutex structure, spin locks are needed to mutually exclude each other, so spin locks are a lower-level means.
  • Mutex is process-level, used for mutual exclusion of resources between multiple processes. Although it is also in the kernel, the execution path of the kernel is based on the identity of the process and competes for resources on behalf of the process. If the competition fails, a process context exchange will occur, the current process enters a sleep state, and the CPU will run other processes. In view of the high overhead of process context switching, mutex is a better choice only when the process takes a long time .
  • When the access time of the critical section to be protected is short, it is very convenient to use a spin lock because it can save the time of context switching. However, if the CPU cannot get the spin lock, it will idle there until the other execution units are unlocked. Therefore, the lock must not stay in the critical region for a long time, otherwise it will reduce the efficiency of the system.

Therefore, there are 3 principles for choosing spin locks and mutexes:

  1. When the lock cannot be acquired, the cost of using the mutex is the process context switching time, and the cost of using the spin lock is waiting to acquire the spin lock (determined by the execution time of the critical section). If the critical region is small, choose a spin lock, if the critical region is large, use a mutex.
  2. ** The critical section protected by the mutex can contain code that may cause blocking, and the spin lock must be absolutely avoided to protect the critical section containing such code. **Because blocking means that the process is switched, if the process is switched out, another process attempts to acquire the spin lock, it means it will happen.
  3. The mutex exists in the context of the process. Therefore, if the protected shared resource needs to be used in an interrupt or soft interrupt situation, only a spin lock can be selected between the mutex and the spin lock. Of course, if you must use a mutex, you can only do it through mutex_trylock(). If you can't get it, return immediately to avoid blocking.

This article examines the book Song Baohua-"Detailed Explanation of Linux Device Driver Development-Based on the Latest Linux 4.0 Kernel"

Guess you like

Origin blog.csdn.net/qq_41782149/article/details/105614655