校正文档.

Signed-off-by: chen.yang <chen.yang@yuzhen-iot.com>
This commit is contained in:
chen.yang 2022-04-18 20:03:21 +08:00
parent 4192c11fd0
commit e270b9f71f

View File

@ -29,7 +29,7 @@ local_bh_enable(); // 使能中断的底半部
要点:关中断时间不可过长,如果有复杂的任务需要处理则应该考虑其他机制实现。 要点:关中断时间不可过长,如果有复杂的任务需要处理则应该考虑其他机制实现。
local_irq_disable()和 local_irq_enable()都只能禁止和使能本 CPU 核内的中断因此并不能解决多CPU 核心引发的竞态问题。因此,单独使用中断屏蔽通常不是一种值得推荐的避免竞态的方法,它适宜与自旋锁联合使用。 local_irq_disable() 和 local_irq_enable() 都只能禁止和使能本 CPU 核内的中断,因此,并不能解决多 CPU 核心引发的竞态问题。因此,单独使用中断屏蔽通常不是一种值得推荐的避免竞态的方法,它适宜与自旋锁联合使用。
## 原子操作 ## 原子操作
@ -84,7 +84,7 @@ spin_unlock(lock) // 释放自旋锁
```cpp ```cpp
spin_lock_irq(); // = spin_lock() + local_irq_disable() spin_lock_irq(); // = spin_lock() + local_irq_disable()
spin_unlock_irq(); // = spin_unlock() + local_irq_enable() spin_unlock_irq(); // = spin_unlock() + local_irq_enable()
spin_lock_irqsave(); // = spin_unlock() + local_irq_save() spin_lock_irqsave(); // = spin_lock() + local_irq_save()
spin_unlock_irqrestore(); // = spin_unlock() + local_irq_restore() spin_unlock_irqrestore(); // = spin_unlock() + local_irq_restore()
spin_lock_bh(); // = spin_lock() + local_bh_disable() spin_lock_bh(); // = spin_lock() + local_bh_disable()
spin_unlock_bh(); // = spin_unlock() + local_bh_enable() spin_unlock_bh(); // = spin_unlock() + local_bh_enable()
@ -92,7 +92,7 @@ spin_unlock_bh(); // = spin_unlock() + local_bh_enable()
使用自旋锁需要注意: 使用自旋锁需要注意:
* 自旋锁实际上是忙等锁当锁不可用时CPU 一直循环执行“测试并设置”该锁直到可用而取得该锁CPU 在等待自旋锁时不做任何有用的工作,仅仅是等待。因此,只有在占用锁的时间极短的情况下,使用自旋锁才是合理的。当临界区很大或有共享设备的时候,需要较长时间占用锁,使用自旋锁会降低系统的性能。 * 自旋锁实际上是忙等锁当锁不可用时CPU 一直循环执行“测试并设置”该锁直到可用而取得该锁CPU 在等待自旋锁时不做任何有用的工作,仅仅是等待。因此,只有在占用锁的时间极短的情况下,使用自旋锁才是合理的。当临界区很大或有共享设备的时候,需要较长时间占用锁使用自旋锁会降低系统的性能。
* 自旋锁可能导致系统死锁。引发这个问题最常见的情况是递归使用一个自旋锁,即如果一个已经拥有某个自旋锁的 CPU 想第二次获得这个自旋锁,则该 CPU 将死锁。此外如果进程获得自旋锁之后再阻塞也有可能导致死锁的发生。copy_from_user()、copy_to_user()和 kmalloc()等函数都有可能引起阻塞,因此在自旋锁的占用期间不能调用这些函数。 * 自旋锁可能导致系统死锁。引发这个问题最常见的情况是递归使用一个自旋锁,即如果一个已经拥有某个自旋锁的 CPU 想第二次获得这个自旋锁,则该 CPU 将死锁。此外如果进程获得自旋锁之后再阻塞也有可能导致死锁的发生。copy_from_user()、copy_to_user()和 kmalloc()等函数都有可能引起阻塞,因此在自旋锁的占用期间不能调用这些函数。
### 读写锁 ### 读写锁
@ -172,7 +172,7 @@ do{
## Read-Copy Update ## Read-Copy Update
读-拷贝-更新,写为 RCU。对于被 RCU 保护的共享数据结构,读执行单元不需要获得任何锁就可以访问它,不使用原子指令,因此不会导致锁竞争、内存延迟以及流水线停滞,也不存在死锁问题。 读-拷贝-更新,写为 RCU。对于被 RCU 保护的共享数据结构,读执行单元不需要获得任何锁就可以访问它,不使用原子指令,因此不会导致锁竞争、内存延迟以及流水线停滞,也不存在死锁问题。
使用 RCU 的写执行单元在访问它前需首先复制一个副本然后对副本进行修改最后使用一个回调机制在适当的时机把指向原来数据的指针重新指向新的被修改的数据这个时机就是所有引用该数据的CPU 都退出对共享数据的操作的时候。读执行单元没有任何同步开销,而写执行单元的同步开销则取决于使用的写执行单元间的同步机制。 使用 RCU 的写执行单元在访问它前需首先复制一个副本然后对副本进行修改最后使用一个回调机制在适当的时机把指向原来数据的指针重新指向新的被修改的数据这个时机就是所有引用该数据的CPU 都退出对共享数据的操作的时候。读执行单元没有任何同步开销,而写执行单元的同步开销则取决于使用的写执行单元间的同步机制。
@ -196,7 +196,7 @@ rcu_read_unlock_bh();
synchronize_rcu(); synchronize_rcu();
``` ```
该函数由 RCU 写执行单元调用,它将阻塞写执行单元,直到所有的读执行单元已经完成读执行单元临界区,写执行单元才可以继续下一步操作。如果有多个 RCU 写执行单元调用该函数,它们将在一个 grace period即所有的读执行单元已经完成对临界区的访问之后全部被唤醒。synchronize_rcu()保证所有 CPU 都处理完正在运行的读执行单元临界区。 该函数由 RCU 写执行单元调用,它将阻塞写执行单元,直到所有的读执行单元已经完成读执行单元临界区,写执行单元才可以继续下一步操作。如果有多个 RCU 写执行单元调用该函数,它们将在一个 grace period即所有的读执行单元已经完成对临界区的访问之后全部被唤醒。synchronize_rcu() 保证所有 CPU 都处理完正在运行的读执行单元临界区。
### 挂接回调 ### 挂接回调
@ -246,13 +246,13 @@ int down_interruptible(struct semaphore * sem);
int down_trylock(struct semaphore * sem); int down_trylock(struct semaphore * sem);
``` ```
使用可被中断的信号量版本的意思是,万一出现了 semaphore 的死锁,还有机会用 ctrl+c 发出软中断,让等待这个内核驱动返回的用户态进程退出。而不是把整个系统都锁住了。在休眠时,能被中断信号终止,这个进程是可以接受中断信号的!比如你在命令行中输入: 使用可被中断的信号量版本的意思是,万一出现了 semaphore 的死锁,还有机会用 Ctrl+C 发出软中断,让等待这个内核驱动返回的用户态进程退出。而不是把整个系统都锁住了。在休眠时,能被中断信号终止,这个进程是可以接受中断信号的!比如你在命令行中输入:
```bash ```bash
sleep 10000 sleep 10000
``` ```
按下 ctrl+c,就给上面的进程发送了进程终止信号。信号发送给用户空间,然后通过系统调用,会把这个信号传给递给驱动,进而避免无限期等待下去。 按下 Ctrl+C,就给上面的进程发送了进程终止信号。信号发送给用户空间,然后通过系统调用,会把这个信号传给递给驱动,进而避免无限期等待下去。
释放信号量方法如下: 释放信号量方法如下:
@ -289,7 +289,7 @@ void complete_all(struct completion *c);
信号量所保护的临界区可包含可能引起阻塞的代码,而自旋锁则绝对要避免用来保护包含这样代码的临界区。因为阻塞意味着要进行进程的切换,如果进程被切换出去后,另一个进程企图获取本自旋锁,死锁就会发生。 信号量所保护的临界区可包含可能引起阻塞的代码,而自旋锁则绝对要避免用来保护包含这样代码的临界区。因为阻塞意味着要进行进程的切换,如果进程被切换出去后,另一个进程企图获取本自旋锁,死锁就会发生。
信号量存在于进程上下文,因此,如果被保护的共享资源需要在中断或软中断情况下使用,则在信号量和自旋锁之间只能选择自旋锁。当然,如果一定要使用信号量,则只能通过 down_trylock()方式进行,不能获取就立即返回以避免阻塞。 信号量存在于进程上下文,因此,如果被保护的共享资源需要在中断或软中断情况下使用,则在信号量和自旋锁之间只能选择自旋锁。当然,如果一定要使用信号量,则只能通过 down_trylock() 方式进行,不能获取就立即返回以避免阻塞。
### 读写信号量 ### 读写信号量