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 设备驱动中必须要解决的一个问题是多个进程对共享的资源的并发访问,并发的访问会导致竞态,即使是经验丰富的驱动工程师也常常设计出包含并发问题bug 的驱动程序。 一、基础概念 1、Linu...
  • zqixiao_09
  • zqixiao_09
  • 2016-03-15 19:26:31
  • 3004

《Linux4.0设备驱动开发详解》笔记--第七章:Linux设备中的并发控制

7.1 并发与竞态 并发是指多个执行单元同时、并发的被执行,而并发的执行单元对共享资源(硬件资源、软件上的的全局变量、静态变量等)的访问则很容易导致竟态 竟态发生在以下几种情况 对称多处理器(SMP...
  • z1106609486
  • z1106609486
  • 2016-05-19 14:37:21
  • 3706

Linux设备程序中的并发控制

一、并发与竞态       并发指多个执行单元同时、并行被执行,而并发的执行单元对共享资源(全局变量,静态变量)的访问则容易导致竞态。      几种情景:1、对称多处理器(SMP)的多个CPU ...
  • jeffade
  • jeffade
  • 2012-05-29 09:49:28
  • 316

Linux并发控制

自旋锁 自旋锁是专为防止多处理器并发而引入的一种锁,它应用于中断处理等部分。对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,不需要自旋锁。自旋锁最多只能被一个内核任务持有,如果一个...
  • chinahex
  • chinahex
  • 2016-01-14 09:28:11
  • 504

Linux驱动设备中的并发控制

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

Linux程序并发控制机制

并发(concurrency)指的是多个执行单元同时、并行被执行。而并发的执行单元对共享资源(硬件资源和软件上的全局、静态变量)的访问则容易导致竞态(race conditions)。    SMP...
  • savionchen
  • savionchen
  • 2014-11-28 11:10:34
  • 238

数据库并发控制知识点总结

刚看到一篇很不错的数据库并发控制知识点总结,包括一部分可能会出现在笔试面试中的题目,适合对基础概念理解不透彻的我,就转载过来了。  原文地址:http://blog.csdn.net/xiangmi...
  • sunsfan
  • sunsfan
  • 2016-08-28 13:13:40
  • 1793

linux 并发控制总结

Atomic_t Atomic_t atom = ATOMIC_INIT(1); Atomic_dec_and_test(&atom); Atomic_inc(&atom); Sp...
  • just_white
  • just_white
  • 2014-02-04 22:44:23
  • 484

分布式系统阅读笔记(十六)-----事务和并发控制

介绍 在分布式系统中,事务的运用和共享资源的并发控制是非常常见的。简单的说,事务就是一些原子的操作的集合。原子操作的意思就是要么操作成功要么操作失败,没有其他的选择。并发控制是出现在高并发场景的时候...
  • Androidlushangderen
  • Androidlushangderen
  • 2015-01-16 15:09:39
  • 2864

数据库并发控制的基本方法

  • 2009年12月21日 23:25
  • 372KB
  • 下载
收藏助手
不良信息举报
您举报文章:Linux设备中的并发控制
举报原因:
原因补充:

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