参考:html
http://www.360doc.com/content/12/0723/00/9298584_225900606.shtmllinux
http://www.cnblogs.com/biyeymyhjob/archive/2012/07/21/2602015.html并发
http://blog.chinaunix.net/uid-25100840-id-3147086.html函数
http://blog.csdn.net/u012719256/article/details/52670098测试
-------------------------------------------------------------------------------------------------ui
在驱动程序中,当多个线程同时访问相同的资源时(驱动程序中的全局变量是一种典型的共享资源),可能会引起"竞态",所以咱们必须对共享资源进行并发控制。Linux内核中解决并发控制的最经常使用方法是自旋锁与信号量(绝大多数时候做为互斥锁使用)。
自旋锁与信号量"相似而不类",相似说的是它们功能上的类似性,"不类"指代它们在本质和实现机理上彻底不同,不属于一类。
自旋锁不会引发调用者睡眠,若是自旋锁已经被别的执行单元保持,调用者就一直循环查看是否该自旋锁的保持者已经释放了锁,"自旋"就是"在原地打转"。而信号量则引发调用者睡眠,它把进程从运行队列上拖出去,除非得到锁。这就是它们的"不类"。
可是,不管是信号量,仍是自旋锁,在任什么时候刻,最多只能有一个保持者,即在任什么时候刻最多只能有一个执行单元得到锁。这就是它们的"相似"。
鉴于自旋锁与信号量的上述特色,通常而言,自旋锁适合于保持时间很是短的状况,它能够在任何上下文使用;信号量适合于保持时间较长的状况,会只能在进程上下文使用。若是被保护的共享资源只在进程上下文访问,则能够以信号量来保护该共享资源,若是对共享资源的访问时间很是短,自旋锁也是好的选择。可是,若是被保护的共享资源须要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。 atom
与信号量相关的API主要有:
定义信号量
spa
1、信号量操作系统
信号量又称为信号灯,它是用来协调不一样进程间的数据对象的,而最主要的应用是共享内存方式的进程间通讯。本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取情况。通常说来,为了得到共享资源,进程须要执行下列操做:
(1) 测试控制该资源的信号量。
(2) 若此信号量的值为正,则容许进行使用该资源。进程将信号量减1。
(3) 若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1)。
(4) 当进程再也不使用一个信号量控制的资源时,信号量值加1。若是此时有进程正在睡眠等待此信号量,则唤醒此进程。
维护信号量状态的是Linux内核操做系统而不是用户进程。咱们能够从头文件/usr/src/linux/include/linux/sem.h 中看到内核用来维护信号量状态的各个结构的定义。信号量是一个数据集合,用户能够单独使用这一集合的每一个元素。要调用的第一个函数是semget,用以得到一个信号量ID。Linux2.6.26下定义的信号量结构体:.net
struct semaphore sem; |
初始化信号量
void sema_init (struct semaphore *sem, int val); |
该函数初始化信号量,并设置信号量sem的值为val
void init_MUTEX (struct semaphore *sem); |
该函数用于初始化一个互斥锁,即它把信号量sem的值设置为1,等同于sema_init (struct semaphore *sem, 1);
void init_MUTEX_LOCKED (struct semaphore *sem); |
该函数也用于初始化一个互斥锁,但它把信号量sem的值设置为0,等同于sema_init (struct semaphore *sem, 0);
得到信号量
void down(struct semaphore * sem); |
该函数用于得到信号量sem,它会致使睡眠(这个睡眠和下面所说的不知道有什么不一样,既然不能被其它地方唤醒,那么这个down有什么用呢?),所以不能在中断上下文使用;
int down_interruptible(struct semaphore * sem); |
该函数功能与down相似,不一样之处为,down不能被信号打断,但down_interruptible能被信号打断;(这个能被信号打断,有点疑惑,我如今作的项目是使用的是被中断打断,不知道它这个地方所说的是什么意思)
int down_trylock(struct semaphore * sem); |
该函数尝试得到信号量sem,若是可以马上得到,它就得到该信号量并返回0,不然,返回非0值。它不会致使调用者睡眠,能够在中断上下文使用。
释放信号量
void up(struct semaphore * sem); |
该函数释放信号量sem,唤醒等待者。
互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(因此名为互斥体(mutex))。互斥体禁止多个线程同时进入受保护的代码“临界区”(critical section)。所以,在任意时刻,只有一个线程被容许进入这样的代码保护区。mutex其实是count=1状况下的semaphore。
1 // 结构
2 struct mutex { 3 /* 1: unlocked, 0: locked, negative: locked, possible waiters */
4 atomic_t count; 5 spinlock_t wait_lock; 6 struct list_head wait_list; 7 #ifdef CONFIG_DEBUG_MUTEXES 8 struct thread_info *owner; 9 const char *name; 10 void *magic; 11 #endif
12 #ifdef CONFIG_DEBUG_LOCK_ALLOC 13 struct lockdep_map dep_map; 14 #endif
15 };
1 // 定义互斥锁lock
2 mutex_init(struct mutex* lock)
或者直接用 #define DEFINE_MUTEX(LOCK)便可; 3
4 // 获取
5 mutex_lock(struct mutex *lock) 6
7 // 释放
8 mutex_unlock(struct mutex *lock)
struct mutex lock;
mutex_init(&lock);初始化互斥锁
或者直接用 #define DEFINE_MUTEX(LOCK)便可;
#define __MUTEX_INITIALIZER(lockname) \ { .count = ATOMIC_INIT(1) \ , .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \ , .wait_list = LIST_HEAD_INIT(lockname.wait_list) \ __DEBUG_MUTEX_INITIALIZER(lockname) \ __DEP_MAP_MUTEX_INITIALIZER(lockname) } #define DEFINE_MUTEX(mutexname) \ struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) extern void __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key);
三:与自旋锁相关的API主要有:
定义自旋锁
spinlock_t spin; |
初始化自旋锁
spin_lock_init(lock) |
该宏用于动态初始化自旋锁lock
得到自旋锁
spin_lock(lock) |
该宏用于得到自旋锁lock,若是可以当即得到锁,它就立刻返回,不然,它将自旋在那里,直到该自旋锁的保持者释放;
spin_trylock(lock) |
该宏尝试得到自旋锁lock,若是能当即得到锁,它得到锁并返回真,不然当即返回假,实际上再也不"在原地打转";
释放自旋锁
spin_unlock(lock) |
该宏释放自旋锁lock,它与spin_trylock或spin_lock配对使用;除此以外,还有一组自旋锁使用于中断状况下的API。