Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5760436
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: LINUX

2009-08-18 16:38:47

spinlock,也称自旋锁。自旋锁最多只能被一个可执行线程持有。如果一个可执行线程试图获得一个被争用(已经被持有的)自旋锁,那么该线程就会一直进行忙等待,自旋,也就是空转,等待锁重新可用。如果锁未被争用,请求锁的执行线程便立刻得到它,继续执行。

一个被争用的自旋锁使得请求它的线程在等待锁重新可用时自旋,特别的浪费CPU时间,所以自旋锁不应该被长时间的持有。实际上,这就是自旋锁的设计初衷,在短时间内进行轻量级加锁。

Kernel中的自旋锁不能够在能够导致睡眠的环境中使用。举个例子,一个线程A获得了自旋锁L;这个时候,发生了中断,在对应的中断处理函数B中,也尝试获得自旋锁L,就会中断处理程序进行自旋。但是原先锁的持有者只有在中断处理程序结束后,采用机会释放自旋锁,从而导致死锁。

我们看一下spinlock在pthread中的实现,即pthread_spin_lock:
#ifndef LOCK_PREFIX
# ifdef UP
#  define LOCK_PREFIX    /* nothing */
# else
#  define LOCK_PREFIX    "lock;"
# endif
#endif


int
pthread_spin_lock (lock)
     pthread_spinlock_t *lock;
{
  asm ("\n"
       "1:\t" LOCK_PREFIX "decl %0\n\t"
       "jne 2f\n\t"
       ".subsection 1\n\t"
       ".align 16\n"
       "2:\trep; nop\n\t"
       "cmpl $0, %0\n\t"
       "jg 1b\n\t"
       "jmp 2b\n\t"
       ".previous"
       : "=m" (*lock)
       : "m" (*lock));

  return 0;
}

这里需要对汇编代码稍微了解一下。
LOCK_PREFIX是为了在SMP下锁总线,保证接下来一条指令的原子性。

%0这里是*lock的值,先将lock的值减一,如果ZF=0(lock值不为0),跳到下面的2标签处继续执行;否则执行结束(lock值为0)。
关于jne,在Intel白皮书里的解释:
jne: Jump near if not equal (ZF=0). Not supported in 64-bit mode.

下面继续看2标签处的代码:
rep nop为实际上为多个nop指令,具体可以参考1中的讨论。
接着比较lock与0的大小,当发现Lock大于0的时候,跳回到1标签,尝试重新获得锁;否则,跳回到标签2继续进行循环。

--------------------------------------
标签1处的代码,在尝试获得锁的时候,直接将lock值减1,如果获得锁操作失败的时候,实际上lock值已经被减了1。这样会不会有问题呢?
实际上,这个问题不用担心,因为在释放锁的时候,lock的值还会被重新设置为1 ;-)
--------------------------------------

这里有一个地方需要注意的就是.subsection和.previous之间代码,与之前的代码不在一个代码段中。由于考虑到大部分情况下,lock都会成功返回,将lock失败后的操作跟之前的代码分开,会提高高速缓存的效率(有限的高速缓存可以放置更多的数据)。

对于pthread_spin_unlock()就简单很多了,只是简单的将lock值设置为1,并返回0:
    .globl    pthread_spin_unlock
    .type    pthread_spin_unlock,@function
    .align    16
pthread_spin_unlock:
    movl    4(%esp), %eax
    movl    $1, (%eax)
    xorl    %eax, %eax
    ret
    .size    pthread_spin_unlock,.-pthread_spin_unlock

    /* The implementation of pthread_spin_init is identical.  */
    .globl    pthread_spin_init
pthread_spin_init = pthread_spin_unlock


参考:





阅读(5469) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~