自旋锁最初是为了在smp系统上使用而设计。

1.在单处理器非抢占模式下,自旋锁不做任何事情。
#ifdef CONFIG_PREEMPT_COUNT     //支持抢占模式

#define preempt_disable() \
do { \
    inc_preempt_count(); \
    barrier(); \
} while (0)

#define sched_preempt_enable_no_resched() \
do { \
    barrier(); \
    dec_preempt_count(); \
} while (0)

#define preempt_enable_no_resched() sched_preempt_enable_no_resched()

#define preempt_enable() \
do { \
    preempt_enable_no_resched(); \
    barrier(); \
    preempt_check_resched(); \
} while (0)

/* For debugging and tracer internals only! */
#define add_preempt_count_notrace(val)          \
    do { preempt_count() += (val); } while (0)
#define sub_preempt_count_notrace(val)          \
    do { preempt_count() -= (val); } while (0)
#define inc_preempt_count_notrace() add_preempt_count_notrace(1)
#define dec_preempt_count_notrace() sub_preempt_count_notrace(1)

#define preempt_disable_notrace() \
do { \
    inc_preempt_count_notrace(); \
    barrier(); \
} while (0)

 
#define preempt_enable_no_resched_notrace() \
do { \
    barrier(); \
    dec_preempt_count_notrace(); \
} while (0)

/* preempt_check_resched is OK to trace */
#define preempt_enable_notrace() \
do { \
    preempt_enable_no_resched_notrace(); \
    barrier(); \
    preempt_check_resched(); \
} while (0)

#else /* !CONFIG_PREEMPT_COUNT */     //非抢占模式

#define preempt_disable()       do { } while (0)
#define sched_preempt_enable_no_resched()   do { } while (0)
#define preempt_enable_no_resched() do { } while (0)
#define preempt_enable()        do { } while (0)

#define preempt_disable_notrace()       do { } while (0)
#define preempt_enable_no_resched_notrace() do { } while (0)
#define preempt_enable_notrace()        do { } while (0)

#endif /* CONFIG_PREEMPT_COUNT */

 
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# ifdef CONFIG_PROVE_LOCKING
#  define spin_acquire(l, s, t, i)      lock_acquire(l, s, t, 0, 2, NULL, i)
#  define spin_acquire_nest(l, s, t, n, i)  lock_acquire(l, s, t, 0, 2, n, i)
# else
#  define spin_acquire(l, s, t, i)      lock_acquire(l, s, t, 0, 1, NULL, i)
#  define spin_acquire_nest(l, s, t, n, i)  lock_acquire(l, s, t, 0, 1, NULL, i)
# endif
# define spin_release(l, n, i)          lock_release(l, n, i)
#else
# define spin_acquire(l, s, t, i)       do { } while (0)
# define spin_release(l, n, i)          do { } while (0)
#endif
 
#ifdef CONFIG_LOCK_STAT

extern void lock_contended(struct lockdep_map *lock, unsigned long ip);
extern void lock_acquired(struct lockdep_map *lock, unsigned long ip);

#define LOCK_CONTENDED(_lock, try, lock)            \
do {                                \
    if (!try(_lock)) {                  \
        lock_contended(&(_lock)->dep_map, _RET_IP_);    \
        lock(_lock);                    \
    }                           \
    lock_acquired(&(_lock)->dep_map, _RET_IP_);         \
} while (0)

#else /* CONFIG_LOCK_STAT */

#define lock_contended(lockdep_map, ip) do {} while (0)
#define lock_acquired(lockdep_map, ip) do {} while (0)

#define LOCK_CONTENDED(_lock, try, lock) \
    lock(_lock)

#endif /* CONFIG_LOCK_STAT */

 
static inline void spin_lock(spinlock_t *lock)
{
    raw_spin_lock(&lock->rlock);
 
#define raw_spin_lock(lock) _raw_spin_lock(lock)
 
#ifndef CONFIG_INLINE_SPIN_LOCK
void __lockfunc _raw_spin_lock(raw_spinlock_t *lock)
{
    __raw_spin_lock(lock);
}
EXPORT_SYMBOL(_raw_spin_lock);
#endif
 
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
    preempt_disable();
    spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
    LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}   
void do_raw_spin_lock(raw_spinlock_t *lock)
{
    debug_spin_lock_before(lock);
    if (unlikely(!arch_spin_trylock(&lock->raw_lock)))     //当没加自旋锁时,条件判断为假,不会执行下面一句
        __spin_lock_debug(lock);
    debug_spin_lock_after(lock);
}
 
static inline int arch_spin_trylock(arch_spinlock_t *lock)
{
    unsigned long tmp;

__asm__ __volatile__(
"   ldrex   %0, [%1]\n"                         //将lock存在tmp中,若没有人占用锁,则tmp=0;若有人占用锁,tmp=1,直接return0
"   teq %0, #0\n"                                //判断tmp=0就执行下面一句,否则不执行
"   strexeq %0, %2, [%1]"                   //将lock=1,即加锁;写成功tmp=0;不成功tmp=1.
    : "=&r" (tmp)                                   //                                        ^                    ^
    : "r" (&lock->lock), "r" (1)                    //                                  return 1          return 0
    : "cc");

if (tmp == 0) {
        smp_mb();
        return 1;
    } else {
        return 0;
    }
}

 
所以单核非抢占,第一次肯定是未加锁状态,调用trylock()后,若加锁成功则返回1,spin_lock()返回。即不会进入自旋状态。
单核非抢占进入某个锁上的自旋状态,则会永远自旋下去;即,没有任何其他进程能够获得CPU来释放这个锁。出于对此原因的考虑,单核非抢占上的自旋锁被优化为不做任何事情。            
 
2.在单核可抢占的系统中,可能会存在以下问题:
     当进程A对公共资源访问时,我们对临界区加锁:
          由于时间片或更高优先级进程,进程A临界区并没有执行完,cpu转而去执行进程B,而进程B中也涉及到对公共资源的访问,但此时获取不到锁,B可能会一直等锁释放,如果B一直循环等,那么系统会出现死机现象;如果进程以时间片调度,那么需要等到对其他进程都调度扫描一次并再次回到进程A,等到进程A临界区执行完,锁才会释放,那么系统响应的就会很慢。
          由于进程A在执行临界区时来了一个中断,而中断例程里也要访问公共资源, 此时中断例程一直等待锁的释放,而进程A的临界区的锁又没有任何机会被释放,那么单核处理器将一直等待下去,而没有任何响应。
 
那么自旋锁的出现就解决了上述问题,自旋锁本身会处理禁止抢占,那么直到加锁的进程临界区执行完,其他进程才能加锁。那么问题来了,自旋锁不能长时间持有,否则其他等待锁释放的进程将不会被执行。
 
3.多核可抢占系统
     cpu1运行进程A,进程A对公共资源访问,cpu2同时运行进程B,进程B也要对公共资源访问,那么就会存在公共资源被异常修改的问题;好,咋们当cpu1的进程A对公共资源访问时,先得加锁;当cpu2同时运行进程B在要对公共资源访问时,发现已经加锁了,有人在访问,自己必须等待解锁,那么解决了多cpu对公共资源的同时修改的问题。但是,但cpu1的进程c抢占进程A,使得进程c运行,而进程c中也恰好要对公共资源访问,由于进程A还没有解锁,辣么进程c也必须等着解锁,进程A还没有执行完前,不能让当前cpu的其他进程抢占啊,这就又蛋疼啦。
 
但自旋锁能解决该问题,因为自旋锁既有锁的功能也有禁止抢占的功能。
 
 
static inline void arch_spin_lock(arch_spinlock_t *lock)
{
    unsigned long tmp;

__asm__ __volatile__(
"1: ldrex   %0, [%1]\n"          //
"   teq %0, #0\n"                    //若tmp=0,
    WFE("ne")
"   strexeq %0, %2, [%1]\n"
"   teqeq   %0, #0\n"
"   bne 1b"
    : "=&r" (tmp)
    : "r" (&lock->lock), "r" (1)
    : "cc");

smp_mb();
}   

内核并发管理---spin lock的更多相关文章

  1. Linux内核同步机制之(四):spin lock【转】

    转自:http://www.wowotech.net/kernel_synchronization/spinlock.html 一.前言 在linux kernel的实现中,经常会遇到这样的场景:共享 ...

  2. Linux内核同步机制之(五):Read Write spin lock【转】

    一.为何会有rw spin lock? 在有了强大的spin lock之后,为何还会有rw spin lock呢?无他,仅仅是为了增加内核的并发,从而增加性能而已.spin lock严格的限制只有一个 ...

  3. Linux内核同步 - Read/Write spin lock

    一.为何会有rw spin lock? 在有了强大的spin lock之后,为何还会有rw spin lock呢?无他,仅仅是为了增加内核的并发,从而增加性能而已.spin lock严格的限制只有一个 ...

  4. Linux内核内存管理

    <Linux内核设计与实现>读书笔记(十二)- 内存管理   内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己来解决(用户空间的内存错误可以抛给内核来解决). 所有内核 ...

  5. linx 内核 并发与同步 1

    内核并发来源: 1.硬件中断和异常:中断服务程序和被中断的进程可能发生并发访问资源 2.软中断和tasklet,软中断和taklet随时都可能倍调度执行,从而打断当前正在执行 进程的上下文. 3.内核 ...

  6. .NET组件程序设计之线程、并发管理(二)

    .Net组件程序设计之线程.并发管理(二) 2.同步线程 手动同步 监视器 互斥 可等待事件 同步线程 所有的.NET组件都支持在多线程的环境中运行,可以被多个线程并发访问,如果没有线程同步,这样的后 ...

  7. EBS Concurrent Manager(并发管理器)异常处理[final]

    来自:http://blog.itpub.net/35489/viewspace-742191/ 有时候我们在通过 adstpall.sh 关闭应用后,然后再使用adstrtal.sh开启.发现并发 ...

  8. spin lock的理解

    为什么在spin lock保护的代码里面不允许有休眠的操作呢? 因为spin lock不是空实现的前提下(内核没关抢占,或者是SMP打开),spin lock中是关抢占的,如果一个进程A拿到锁,内核抢 ...

  9. Pthreads并行编程之spin lock与mutex性能对比分析(转)

    POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套常用的API.线程同步(Thread Synchronization)是并行编程中非常重要的通讯手段,其中最典型的应用 ...

随机推荐

  1. [CF678F]Lena and Queries

    题意: 初始有一个空集合$n$个操作有三种操作,如下:$1\ a\ b$表示向集合中插入二元组$(a,b)$$2\ i$表示删除第$i$次操作时所插入的二元组$3\ q$表示询问当前集合的二元组中,$ ...

  2. 【计算几何】【辛普森积分法】UVALive - 7076 - Highway

    春节前后想了好久才在队友的讲解下想明白…… 太难讲了,我就不讲了,大概就是考虑直着走到高速上还是斜着走到高速上,然后平移直线和大圆相切,把生成的最大的“桥”和大圆并一下就行了. #include< ...

  3. 显示字符 Exercise06_12

    /** * @author 冰樱梦 * 时间:2018年下半年 * 题目:显示字符 *1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J ...

  4. 《深入理解Spark-核心思想与源码分析》(二)第二章Spark设计理念和基本架构

    若夫乘天地之正,而御六气之辩解,以游无穷者,彼且恶乎待哉? ——<庄子.逍遥游> 翻译:至于遵循宇宙万物的规律,把握“六气”的变化,遨游于无穷无尽的境域,他还仰赖什么呢! 2.1 初始Sp ...

  5. 导出pem证书给服务端Push Notification使用

    1. 钥匙串创建Push证书的证书签名请求文件(CSR文件). 如下图所示: 2.创建App ID,创建Provisioning Profile,下载安装到XCode. 苹果开发者后台页面,创建Pus ...

  6. windbg --sqlserver 实例 转

    http://blog.csdn.net/obuntu/article/details/5962378 SQLSERVER DUMP 调试 在下面的对话框输入 ~ 会出现线程的信息 0:000> ...

  7. FindFirstVolume系列函数遍历驱动器,获取驱动器信息

    什么是“卷”?卷,又称为“逻辑驱动器”,是 NTFS, FAT32 等文件系统组织结构的最高层.卷是存储设备(如硬盘)上由文件系统管理的一块区域,是在逻辑上相互隔离的存储单元.一个磁盘分区至少包含一个 ...

  8. Delphi 获取sqlite中所有的表名

    取得sqlite数据库里所有的表名 查询table,type 段是'table',name段是table的名字, so: select name from sqlite_master where ty ...

  9. Cesium 事件

    1.相机事件(移动开始.移动结束等等) viewer.scene.camera.moveEnd.addEventListener(function(){ }): 2.鼠标事件(单击.移动.右键等) v ...

  10. 【tomcat】FileNotFoundException: C:\Program Files\Java\apache-tomcat-8.5.11-geneshop3\webapps\ROOT\index.html (拒绝访问。)

    新装系统后,tomcat启动起来 提示如下错误: Caused by: java.io.FileNotFoundException: C:\Program Files\Java\apache-tomc ...