linux 内核的几种锁介绍 http://wenku.baidu.com/link?url=RdvuOpN3RPiC5aY0fKi2Xqw2MyTnpZwZbE07JriN7raJ_L6Ss8Ru1f6C3Gaxl1klYrX8sWGjWV0FJigMFo96Umisnf8cdnccboyczsikpye

一、 以2.6.38以前的内核为例, 讲spinlock、 mutex 以及 semaphore
1. spinlock更原始,效率高,但讲究更多,不能随便用。
2. 个人觉得初级阶段不要去深挖mutex 以及 semaphore的不同,用法类似。在内核代码里面搜索,感觉 DEFINE_MUTEX + mutex_lock_xx + mutex_unlock 用的更多。
3. 在内核里面这三个符号发挥的作用就是: 自旋锁与互斥体。
semaphore:内核中的信号量通常用作mutex互斥体(信号量初值初始化为1,即binary semaphore的方式,就达到了互斥的效果)。
mutex:顾名思义, 互斥体。
所以在内核里面,mutex_lock()和down()的使用情景基本上相同。

//spinlock.h
/******
*API
*spin_lock
*spin_lock_bh
*spin_lock_irq
*spin_trylock
*spin_trylock_bh
*spin_trylock_irq
*spin_unlock
*spin_unlock_bh
*spin_unlock_irq
*spin_unlock_irqrestore
*spin_unlock_wait
******/

//semaphore.h
用 DECLARE_MUTEX 定义了一个count==1 的信号量(binary semaphore)。

#define DECLARE_MUTEX(name)    \
    struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
    
struct semaphore {
    spinlock_t        lock;
    unsigned int        count;
    struct list_head    wait_list;
};

#define __SEMAPHORE_INITIALIZER(name, n)                \
{                                    \
    .lock        = __SPIN_LOCK_UNLOCKED((name).lock),        \
    .count        = n,                        \
    .wait_list    = LIST_HEAD_INIT((name).wait_list),        \
}
    
#define init_MUTEX(sem)        sema_init(sem, 1)
#define init_MUTEX_LOCKED(sem)    sema_init(sem, 0)

/*****
*API:
*#define init_MUTEX(sem)        sema_init(sem, 1)
*#define init_MUTEX_LOCKED(sem)    sema_init(sem, 0)
*extern void down(struct semaphore *sem);
*extern int __must_check down_interruptible(struct semaphore *sem);
*extern int __must_check down_killable(struct semaphore *sem);
*extern int __must_check down_trylock(struct semaphore *sem);
*extern int __must_check down_timeout(struct semaphore *sem, long jiffies);
*extern void up(struct semaphore *sem);
****/

//mutex.h
#define DEFINE_MUTEX(mutexname) \
    struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
    
    #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) }

/*
 * Simple, straightforward mutexes with strict semantics:
 *
 * - only one task can hold the mutex at a time
 * - only the owner can unlock the mutex
 * - multiple unlocks are not permitted
 * - recursive locking is not permitted
 * - a mutex object must be initialized via the API
 * - a mutex object must not be initialized via memset or copying
 * - task may not exit with mutex held
 * - memory areas where held locks reside must not be freed
 * - held mutexes must not be reinitialized
 * - mutexes may not be used in hardware or software interrupt
 *   contexts such as tasklets and timers
 *
 * These semantics are fully enforced when DEBUG_MUTEXES is
 * enabled. Furthermore, besides enforcing the above rules, the mutex
 * debugging code also implements a number of additional features
 * that make lock debugging easier and faster:
 *
 * - uses symbolic names of mutexes, whenever they are printed in debug output
 * - point-of-acquire tracking, symbolic lookup of function names
 * - list of all locks held in the system, printout of them
 * - owner tracking
 * - detects self-recursing locks and prints out all relevant info
 * - detects multi-task circular deadlocks and prints out all affected
 *   locks and tasks (and only those tasks)
 */
struct mutex {
    /* 1: unlocked, 0: locked, negative: locked, possible waiters */
    atomic_t        count;
    spinlock_t        wait_lock;
    struct list_head    wait_list;
#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)
    struct thread_info    *owner;
#endif
#ifdef CONFIG_DEBUG_MUTEXES
    const char         *name;
    void            *magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    struct lockdep_map    dep_map;
#endif
};

/*******
*API:
*extern void mutex_lock(struct mutex *lock);
*extern int __must_check mutex_lock_interruptible(struct mutex *lock);
*extern int __must_check mutex_lock_killable(struct mutex *lock);
*extern void mutex_unlock(struct mutex *lock);
********/

EG1-:
spinlock_t rtc_lock;
spin_lock_init(&rtc_lock);//每个驱动都会事先初始化,只需要这一次初始化 spin_lock_irq(&rtc_lock);
//临界区
spin_unlock_irq(&rtc_lock); EG1-:
unsigned long flags;
static spinlock_t i2o_drivers_lock;
spin_lock_init(&i2o_drivers_lock);//每个驱动都会事先初始化,只需要这一次初始化 spin_lock_irqsave(&i2o_drivers_lock, flags);
//临界区
spin_unlock_irqrestore(&i2o_drivers_lock, flags); EG2:
static DECLARE_MUTEX(start_stop_sem);
down(&start_stop_sem);
//临界区
up(&start_stop_sem); EG3:
static DEFINE_MUTEX(adutux_mutex);
mutex_lock_interruptible(&adutux_mutex);
//临界区
mutex_unlock(&adutux_mutex);

二、 2.6.38以后DECLARE_MUTEX替换成DEFINE_SEMAPHORE(命名改变), DEFINE_MUTEX用法不变

    static DEFINE_SEMAPHORE(msm_fb_pan_sem);// DECLARE_MUTEX
down(&adb_probe_mutex);
//临界区
up(&adb_probe_mutex); static DEFINE_SEMAPHORE(bnx2x_prev_sem);
down_interruptible(&bnx2x_prev_sem);
//临界区
up(&bnx2x_prev_sem);

Linux 2.6.36以后file_operations和DECLARE_MUTEX 的变化http://blog.csdn.net/heanyu/article/details/6757917

在include/linux/semaphore.h 中将#define DECLARE_MUTEX(name)   改成了 #define DEFINE_SEMAPHORE(name)   【命名】

     
三、自旋锁与信号量
1. 自旋锁
简单的说,自旋锁在内核中主要用来防止多处理器中并发访问临界区,防止内核抢占造成的竞争。【适用于多处理器】【自旋锁会影响内核调度】
另外自旋锁不允许任务睡眠(持有自旋锁的任务睡眠会造成自死锁——因为睡眠有可能造成持有锁的内核任务被重新调度,而再次申请自己已持有的锁),它能够在中断上下文中使用。【不允许任务睡眠】

锁定一个自旋锁的函数有四个:
void spin_lock(spinlock_t *lock); //最基本得自旋锁函数,它不失效本地中断。
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);//在获得自旋锁之前禁用硬中断(只在本地处理器上),而先前的中断状态保存在flags中
void spin_lockirq(spinlock_t *lock);//在获得自旋锁之前禁用硬中断(只在本地处理器上),不保存中断状态
void spin_lock_bh(spinlock_t *lock);//在获得锁前禁用软中断,保持硬中断打开状态

2. 信号量
内核中的信号量通常用作mutex互斥体(信号量初值初始化为1就达到了互斥的效果)。

如果代码需要睡眠——这往往是发生在和用户空间同步时——使用信号量是唯一的选择。由于不受睡眠的限制,使用信号量通常来说更加简单一些。【信号量使用简单】
如果需要在自旋锁和信号量中作选择,应该取决于锁被持有的时间长短。理想情况是所有的锁都应该尽可能短的被持有,但是如果锁的持有时间较长的话,使用信号量是更好的选择。【如果锁占用的时间较长,信号量更好】
另外,信号量不同于自旋锁,它不会关闭内核抢占,所以持有信号量的代码可以被抢占。这意味者信号量不会对影响调度反应时间带来负面影响。【信号量不会影响内核调度】

3. 使用情景对比
=============================================
需求                     建议的加锁方法 
低开销加锁               优先使用自旋锁
短期锁定                 优先使用自旋锁
长期加锁                 优先使用信号量
中断上下文中加锁         使用自旋锁
持有锁是需要睡眠、调度    使用信号量
=============================================

内核必看: spinlock、 mutex 以及 semaphore的更多相关文章

  1. Linux驱动开发必看详解神秘内核(完全转载)

    Linux驱动开发必看详解神秘内核 完全转载-链接:http://blog.chinaunix.net/uid-21356596-id-1827434.html   IT168 技术文档]在开始步入L ...

  2. 线程同步 –Mutex和Semaphore

    上一篇介绍了同步事件EventWaitHandle,以及它的两个子类型AutoResetEvent和ManualResetEvent.下面接着介绍WaitHandle的另外两个子类型Mutex和Sem ...

  3. Mutex vs Semaphore vs Monitor vs SemaphoreSlim

    C#开发者(面试者)都会遇到Mutex,Semaphore,Monitor,SemaphoreSlim这四个与锁相关的C#类型,本文期望以最简洁明了的方式阐述四种对象的区别. 线程安全 教条式理解 如 ...

  4. Linux网络编程必看书籍推荐

    首先要说讲述计算机网络和TCP/IP的书很多. 先要学习网络知识才谈得上编程 讲述计算机网络的最经典的当属Andrew S.Tanenbaum的<计算机网络>第五版,这本书难易适中. &l ...

  5. Linux经常使用的命令(必看)

    http://www.importnew.com/12425.html     http://www.importnew.com/13107.html http://www.importnew.com ...

  6. Swift 3必看:从使用场景了解GCD新API

    https://www.jianshu.com/p/fc78dab5736f 2016.10.06 21:59* 在学习Swift 3的过程中整理了一些笔记,如果想看其他相关文章可前往<Swif ...

  7. Java编程思想重点笔记(Java开发必看)

    Java编程思想重点笔记(Java开发必看)   Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而 ...

  8. 续评《遇到一位ITer,一位出租车司机,必看》

    链接:<遇到一位ITer,一位出租车司机,必看> 续评:       我算不上严格意义上的共产主义者,但是算是坚定的共富主义者,切忌不能理解为平均主义者.就是说你开个大奔,我最起码也得能开 ...

  9. mutex与semaphore的区别

    网摘1:Mutex 的发音是 /mjuteks/ ,其含义为互斥(体),这个词是Mutual Exclude的缩写.Mutex在计算机中是互斥也就是排他持有的一种方式,和信号量-Semaphore有可 ...

随机推荐

  1. .net 更改日期格式

    示例:更改日期格式 下面的代码示例使用 Regex.Replace 方法将 mm/dd/yy 格式的日期替换为 dd-mm-yy 格式的日期. static string MDYToDMY(strin ...

  2. javascript模块化编程(转载)

    Javascript 模块化编程 作者: 阮一峰  发布时间: 2013-01-08 18:04  阅读: 7632 次  推荐: 40   原文链接   [收藏]   随着网站逐渐变成"互 ...

  3. poj 2007 Scrambled Polygon 极角排序

    /** 极角排序输出,,, 主要atan2(y,x) 容易失精度,,用 bool cmp(point a,point b){ 5 if(cross(a-tmp,b-tmp)>0) 6 retur ...

  4. ID卡

    ID卡全称为身份识别卡(Identification Card),是一种不可写入的感应卡,含固定的编号,主要有台湾SYRIS的EM格式.美国HIDMOTOROLA等各类ID卡.ID卡与磁卡一样,都仅仅 ...

  5. BZOJ 1058 报表统计 (STL)

    题解:数据结构的基本操作,用STL可以完美实现,就是比较慢…… #include <cstdio> #include <map> #include <set> #i ...

  6. rpc的学习

    rpc(Remote process call 即远程过程调用)是一种请求-相应的协议, 主要使用于C/S架构中,使得分布式系统成为可能.由客户端发起请求,服务端调用各种参数处理请求,当服务器在处理请 ...

  7. [置顶] P2P网贷对推动社会发展的影响

    P2P网贷对推动社会发展的影响 1 真正的支持了实体经济,一般借款人就在几万或者50万以下 2 关照小微经济,新型行业.一般小微经济的创新更高,对社会的发展最大化. 3盘活存量 放到银行.保险.国债一 ...

  8. 带你轻松玩转Git--图解三区结构

    在上篇文章的结尾我们提到了Git 的三区结构,在版本控制体系中有这样两种体系结构,一种是两区结构一种是三区结构.接下来我们通过对Git三区的结构学习来帮助我们更好的去理解并运用Git. 两区结构是其他 ...

  9. [python网络编程]DNSserver

    在上一篇中,使用scrapy改动源IP发送请求的最后我们提到因为hosts文件不支持正则,会导致我们的随机域名DNS查询失败. 使用DNS代理服务器能够解决问题, 以下是我用gevent写的小工具.非 ...

  10. tomcat配置没啥难的啊

    总体上就是: 1.下载jdk并安装. 2.下载tomcat 3.分别设置好环境变量. 4.cmd java -version 如果成功,证明java jdk配置OK startup.bat 如果成功 ...