Linux设备中的并发控制

原创 2012年09月20日 09:04:40

并发执行的唯一原因是:硬件中断服务。内核代码是可抢占的。
什么是竞争?当 2 个执行的线路[有机会操作同一个数据结构(或者硬件资源), 混合的可能性就一直存在。
避免竞争方法:
       在你设计驱动时在任何可能的时候记住避免共享的资源. 如果没有并发存取, 就没有竞争情况. 因此小心编写的内核代码应当有最小的共享. 这个想法的最明显应用是避免使用全局变量. 如果你将一个资源放在多个执行线路能够找到它的地方, 应当有一个很强的理由这样做。全局变量不是共享资源的唯一方法,传递一个指针给内核的其他代码,潜在的创造了一个新的共享形式。
       存取管理的常用技术是加锁或者互斥,确保在任何时间内只有一个执行线程可以操作一个共享资源。
当内核代码创建一个会被内核其他部分共享的对象时, 这个对象必须一直存在(并且功能正常)到它知道没有对它的外部引用存在为止。
临界区:在任何给定的时间内只有一个线程可以执行代码。
旗标(信号量):是一个整型值,结合一对函数,一个像进入临界区的进程将调用相关旗标的P,如果旗标的值大于0,这个值将减一并且继续进程。相反,如果旗标的值是0(或者更小),进程必须等待别的进程释放旗标,解锁旗标通过调用V完成,这个函数会增加旗标的值,并且。如果需要,可以唤醒等待的进程。
当旗标初始化为1时,就成了互斥锁。
初始化:void sema_init(struct semaphore *sem, int val)    /* val 表示初始化值 */
互斥锁初始化: DECLARE_MUTEX(name);              /* 1 name为信号量变量*/
                            DECLARE_MUTEX_LOCKED(name);       /* 0 同上*/ 
动态初始化(运行时):
void init_MUTEX(struct semaphore *sem);
void init_MUTEX_LOCKED(struct semaphore *sem);
P函数成为down—或者这个名字的变体:作用是是信号量减一,并且可能使调用者睡眠一会,等到旗标变为可用之后,再对共享资源进行存取。
void down(struct semaphore * sem);          /* 递减信号量,并等待需要的时间 */
int down_interruptible(struct semaphore *sem); /* 可被中断的:允许一个在等待用户空间的进程被用户中断 */
int down_trylock(struct semaphore *sem);     /* 从不睡眠 */
V函数:void up(struct semaphore *sem);  /* 当持有一个旗标时遇到一个错误时,旗标必须在返回错误状态之前释放旗标。
注意:旗标必须在设备对系统的其他部分可用前初始化。
read and write semaphore:
down_read(struct rm_semaphore *sem);  --------  down_write(struct rm_semaphore *sem)
int down_read_trylock(struct rw_semaphore *sem);  -----  down_write_trylock(struct rw_semaphore *sem);
void up_read(struct rw_semaphore *sem);  ---- void up_write(struct rw_semaphore *sem);
void downgrade_write(struct rw_semaphore *sem); //一旦完成改变后允许其他read进入。
what is the meaning of Completions?
允许一个线程告诉另一个线程工作已经完成。
一个completion的创建:
<linux/completion.h>
DDECLARE_COMLETION(my_completion);
动态创建和初始化:
struct completion my_completion;
init_completion( &my_completion);
简单的调用:
void wait_for_completion(struct completion *c)  //如果没有人完成这个任务,结果会是一个不可杀死的进程。
一般调用:
void complete(struct completion *c);   /* 一个等待进程 */
void complete_all(struct completion *c); /* 多个等待进程 */
what is the meaning of spinlock?
background: 大部分加锁是有一种自旋锁机制来实现;
special case:自旋锁可用在不能睡眠的代码中,例如中断处理;
concept:互斥设备,上锁和解锁;如果锁是可用的, 这个"上锁"位被置位并且代码继续进入临界区. 相反, 如果这个锁已经被别人获得, 代码进入一个紧凑的循环中反复检查这个锁, 直到它变为可用. 这个循环就是自旋锁的"自旋"部分。(简单的形式并不是好的形势)
要求:原子操作;在超线程上避免死锁。
#include<linux/spinlock.h>
初始化定义:spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
或者在运行时使用:void spin_lock_init(spinlock_t *lock);
在进入一个临界区时,代码必须获得需要的lock:
void spin_lock(spinlock_t *lock);  /* 由于不可中断 自旋直到锁变为可用*/
释放锁:
void spin_unlock(spinlock_t *lock);
原则上:不能睡眠;不能因为任何原因放弃处理器,除了服务中断(并且有时即便如此也不行);自旋锁必须一直是尽可能短时间得持有。
原因:内核抢占;睡眠可能发生在从用户空间拷贝数据,分配内存的任何操作等等;中断在获得自旋操作之后,但是中断操作中的代码又需要获得这把锁,这就会发生永久的自旋。(避免这个陷阱需要在持有自旋锁时禁止中断)
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock)
void spin_unlock(spinlock_t *lock);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_unlock_irq(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);
陷阱锁:模糊的规则 加锁顺序规则 细 – 粗 – 粒度加锁
原子变量:<asm/atomic.h>
void atomic_set(atomic_t *v, int i); 
atomic_t v = ATOMIC_INIT(0); 
设置原子变量 v 为整数值 i. 你也可在编译时使用宏定义 ATOMIC_INIT 初始化原子值.
int atomic_read(atomic_t *v); 
返回 v 的当前值.
void atomic_add(int i, atomic_t *v); 
由 v 指向的原子变量加 i. 返回值是 void, 因为有一个额外的开销来返回新值, 并且大部分时间不需要知道它.
void atomic_sub(int i, atomic_t *v); 
从 *v 减去 i.
void atomic_inc(atomic_t *v); 
void atomic_dec(atomic_t *v); 
递增或递减一个原子变量.
int atomic_inc_and_test(atomic_t *v); 
int atomic_dec_and_test(atomic_t *v); 
int atomic_sub_and_test(int i, atomic_t *v); 
进行一个特定的操作并且测试结果; 如果, 在操作后, 原子值是 0, 那么返回值是真; 否则, 它是假. 注意没有 atomic_add_and_test.
int atomic_add_negative(int i, atomic_t *v); 
加整数变量 i 到 v. 如果结果是负值返回值是真, 否则为假.
位操作:<asm/bitops.h>
void set_bit(nr, void *addr); 
设置第 nr 位在 addr 指向的数据项中.
void clear_bit(nr, void *addr); 
清除指定位在 addr 处的无符号长型数据. 它的语义与 set_bit 的相反.
void change_bit(nr, void *addr); 
翻转这个位.
test_bit(nr, void *addr); 
这个函数是唯一一个不需要是原子的位操作; 它简单地返回这个位的当前值.






版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

linux设备驱动中的并发控制

在linux设备驱动中必须解决的一个问题是多个进程对互斥资源的并发访问,并发的访问会导致竞态。 1.1 并发与竟态 并发指多个执行单元同时、并发的被执行,而并发的执行单元对共享资源的访问很容易导致竟态...

Linux 设备驱动 ====> 并发控制 --- 原子操作

原子操作 原子的操作指的就是在执行过程中不会被别的代码所中断的操作。 在Linux中原子操作的方法有很多,有整型原子和位原子,他们在任何情况下操作都是原子的,这些原子操作的实现都是依赖CPU来实现...

深入浅出Linux设备驱动之并发控制

在驱动程序中,当多个线程同时访问相同的资源时(驱动程序中的全局变量是一种典型的共享资源),可能会引发"竞态",因此我们必须对共享资源进行并发控制。Linux内核中解决并发控制的最常用方法是自旋锁与信号...

Linux驱动设备中的并发控制

一、基本概念二、中断屏蔽三、原子操作四、自旋锁五、信号量六、互斥体 七、自旋锁与信号量的比较  Linux设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发的访问会导致竞态,即使是经验...

Linux 设备驱动 ====> 并发控制 --- 原子操作

原子操作 原子的操作指的就是在执行过程中不会被别的代码所中断的操作。 在Linux中原子操作的方法有很多,有整型原子和位原子,他们在任何情况下操作都是原子的,这些原子操作的实现都是依赖CP...

Linux设备驱动中的并发控制

对并发的管理是操作系统编程中核心的问题之一。 并发产生竞态,竞态导致共享数据的非法访问。因为竞态是一种极端低可能性的事件,因此程序员往往会忽视竞态。但是在计算机世界中,百万分之一的事件可能没几秒就会发...

Linux设备驱动中的并发控制---信号量

Linux 设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发访问会导致竞态。  1、并发与竞态 并发(concurrency)指的是多个执行单元同时、并行被执行,而并发的执行单元对共享...

7、linux设备驱动--并发控制

1.并发与竞态 并发指的是多个执行单元同时、并行被执行,而并发的执行单元对共享资源(全局变量、静态变量)的访问容易导致竞态。           2.中断屏蔽
  • mianyy
  • mianyy
  • 2011-08-23 14:50
  • 1151

对linux设备驱动中的并发控制相关内容的理解

这篇笔记主要是针对linux设备驱动中的并发控制内容的学习后,存在的一些问题的补充学习和调查结果,路过的大神们也可以帮我看看理解的是否正确,有问题的话欢迎大家帮我指出来,小弟在此谢过啦! 问题一 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)