自旋锁 -转载http://www.cnblogs.c…

关于锁,最常使用的便是:自旋锁与信号量。先贴些实例,来点感性的认识。

-- include/linux/spinlock_types.h --
typedef struct {
    raw_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
      unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
      unsigned int magic, owner_cpu;
      void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
      struct lockdep_map dep_map;
#endif
} spinlock_t;

typedef struct {
      volatile unsigned int lock;
} raw_spinlock_t;
以上是 2.6.32中的定义。raw_spinlock_t在 2.6.39中的定义:
typedef struct spinlock {
      union {
              struct raw_spinlock rlock;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))
              struct {
                      u8 __padding[LOCK_PADSIZE];
                      struct lockdep_map dep_map;
              };
#endif
      };
} spinlock_t;

typedef struct raw_spinlock {
      arch_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
      unsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
      unsigned int magic, owner_cpu;
      void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
      struct lockdep_map dep_map;
#endif
} raw_spinlock_t;

typedef struct {
      volatile unsigned int lock;
} arch_spinlock_t;

大体上就是将struct raw_spinlock变肥了而已,对于我们而言,该吃吃,该睡睡,平时如何写代码,现在依旧如何写。只要volatile unsigned int lock在就好。

关于lock变量,涉及到一个“排队自旋锁“的问题,将lock分为三部分:高16位(一般未用),第16位再一分为二(next域,owner域)。
简单的说,申请自旋锁,next++;释放自旋锁,owner++;
if (next<未增值前> == owner)
     能申请自旋锁
else
     不能申请自旋锁

spinlock_t lock = SPIN_LOCK_UNLOCKED;
int __init my_init(void)
 
   
    printk("<0>SPIN_LOCK_UNLOCKED: %d\n",SPIN_LOCK_UNLOCKED.raw_lock.rlock);
   
    spin_lock_init( &lock );  //初始化自旋锁
    printk("<0>after init, lock: %d\n",lock.raw_lock.rlock);
   
    printk("<0>\n");
    spin_lock( &lock );      //第一次获取自旋锁
    printk("<0>first spin_lock, lock: %d\n",lock.raw_lock.rlock);
    spin_unlock( &lock );    //第一次释放自旋锁
    printk("<0>first spin_unlock, lock: %d\n",lock.raw_lock.rlock);
    printk("<0>\n");
    spin_lock( &lock );      //第二次获取自旋锁
    printk("<0>second spin_lock, lock: %d\n",lock.raw_lock.rlock);
    spin_unlock( &lock );    //第二次释放自旋锁
    printk("<0>second spin_unlock, lock: %d\n",lock.raw_lock.rlock);
    return 0;
}
加载结果:
Return
[ 4123.219758] SPIN_LOCK_UNLOCKED: 0
[ 4123.219762] after init, lock: 0
[ 4123.219764]
[ 4123.219765] first spin_lock, lock: 256
[ 4123.219768] first spin_unlock, lock: 257
[ 4123.219770]
[ 4123.219771] second spin_lock, lock: 513
[ 4123.219774] second spin_unlock, lock: 514
加锁是主菜,当然还会有一些附属功能(irq)一并执行,比如下面的三个实例:
(1)
int __init spin_lock_bh_init(void)
  
    spinlock_t lock = SPIN_LOCK_UNLOCKED;  
   
    spin_lock_init( &lock );    //初始化自旋锁
    printk("<0>in_softirq():%ld\n", in_softirq());  //输出软中断计数
    printk("<0>lock........\n");
    spin_lock_bh( &lock);       //获取自旋锁同时禁止软中断
    printk("<0>in_softirq():%ld\n", in_softirq());
    printk("<0>unlock........\n");
    spin_unlock_bh( &lock);     //释放自旋锁同时使能软中断
    printk("<0>in_softirq():%ld\n", in_softirq());
    return 0;
}
--------------------------------------
[ 5065.951735] in_softirq():0
[ 5065.951739] lock........
[ 5065.951741] in_softirq():256
[ 5065.951743] unlock........
[ 5065.951745] in_softirq():0
(2)
int __init spin_lock_irq_init(void)
{
    spinlock_t lock = SPIN_LOCK_UNLOCKED;
    spin_lock_init( &lock );    //初始化自旋锁
    printk("<0>lock........\n");
    spin_lock_irq( &lock);     //获取自旋锁同时禁止本地中断
    printk("<0>irqs_disabled():%d\n",irqs_disabled());  //查看中断是否被禁止
    printk("<0>unlock........\n");
    spin_unlock_irq( &lock);   //释放自旋锁同时使能本地中断
    printk("<0>irqs_disabled():%d\n",irqs_disabled());
    return 0;
}

---------------------------------------
[ 5747.407543] lock........
[ 5747.407548] irqs_disabled():1
[ 5747.407550] unlock........
[ 5747.407552] irqs_disabled():0

(3)
int __init spin_lock_irqsave_init(void)
 
     
      unsigned long flags = 0;
      spinlock_t lock = SPIN_LOCK_UNLOCKED;   
     
      spin_lock_init( &lock );      //初始化自旋锁
     
 
      printk("<0>lock........\n");
      spin_lock_irqsave( &lock, flags );  //先禁止中断,后加锁,将加锁前的中断状态保存在flag     
     
      printk("<0>irqs_disabled():%d\n",irqs_disabled());  //查看中断是否被禁止
      printk("<0>flags = 0x%lx\n",flags);  //输出标志寄存器的值
      printk("<0>unlock........\n");
      spin_unlock_irqrestore( &lock, flags );
      printk("<0>irqs_disabled():%d\n",irqs_disabled());
     
      return 0;
}

--------------------------------------
[ 6197.981793] lock........
[ 6197.981798] irqs_disabled():1
[ 6197.981800] flags = 0x200296
[ 6197.981802] unlock........
[ 6197.981804] irqs_disabled():0
再介绍一个try_lock:
-------trylock的特点在于会有返回值。
spinlock_t lock = SPIN_LOCK_UNLOCKED;
int ret;
int my_function(void * argc)
{
      printk("<0>\nin child, the current pid is:%d\n",current->pid);          //显示子进程PID
      ret = spin_trylock( &lock );
      if( ret == 1 )
      {
              spin_unlock( &lock );
      }
      else
      {
              printk("<0>spin_trylock could't get the lock!\n");
              printk("<0>need the parent to unlock.\n\n");
      }
      return 0;
}
 
int __init spin_trylock_init(void)
{
      int ret0;
      printk("<0>in parent, the current pid is:%d\n",current->pid);    //显示父进程PID
      spin_lock_init( &lock );
      spin_lock( &lock );            //获取自旋锁
      ret0 = kernel_thread(my_function,NULL,CLONE_KERNEL);

      spin_unlock( &lock );      //释放自旋锁
      printk("<0>parent unlock!\n");
      return 0;
}
 

 

-----------

读写自旋锁
-----------

 

读写锁当然也有个lock,低24位为读者计数器(0~23)。
24位为“未锁“标志字段
其他未用。

未锁置1,表示此时锁没人拿。
未锁置0,其他也

typedef struct {
raw_rwlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAK
unsigned
int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
unsigned
int magic, owner_cpu;
void * owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
struct lockdep_map dep_map;
#endif
} rwlock_t;

typedef
struct {
volatile unsigned int lock ;
} raw_rwlock_t;
复制代码

为0,表示写者掌控锁。
未锁置0,低24位有值,表示读者掌控锁,读者的个数表示有点特别,就是:
一个读者,则:0x00ffffff
两个读者,则:0x00fffffe

以此列推,大伙儿都看得出来。

最后来个实例,帮助理解:

rwlock_t rwlock = RW_LOCK_UNLOCKED;
int __init write_trylock_init(void)
{
      int ret;
      rwlock_init( &rwlock );        //读写自旋锁初始化
      read_lock( &rwlock );            //读者申请得到读写锁rwlock
     
      printk("<0>after read_lock,lock: 0x%x\n",rwlock.raw_lock.lock);
     
      printk("<0>\n");
      ret = write_trylock( &rwlock );  //写者试图获得自旋锁
      if( ret == 1 )
       
              printk("<0>after write_trylock, lock: 0x%x\n",rwlock.raw_lock.lock);
              write_unlock( &rwlock );
              printk("<0>after write_unlock, lock: 0x%x\n",rwlock.raw_lock.lock);
       
      else
       
              printk("<0>write_trylock could't get the lock!\n");
       
     
      printk("<0>\n");
      read_unlock( &rwlock );      //读者释放读写锁rwlock
      printk("<0>after read_unlock,lock: 0x%x\n",rwlock.raw_lock.lock);
      return 0;
}
加载结果:
[ 9106.498749] after read_lock,lock: 0xffffff
[ 9106.498753]
[ 9106.498755] write_trylock could't get the lock!
[ 9106.498757]
[ 9106.498759] after read_unlock,lock: 0x1000000
当然,kernel里的锁还有许多,顺序锁啊,信号量啊什么。但基本都是那个样子。再说一个completioin,这个东西初次看到有点唬人,先来个实例:
struct completion {
      unsigned int done;
      wait_queue_head_t  wait;
};
--------------------------------
static struct completion comple;
int my_function(void * argc)
{
      wait_queue_head_t head;
      wait_queue_t data;
      printk("<0>in the kernel thread function!\n");
      init_waitqueue_head(&head);
      init_waitqueue_entry(&data,current);
      add_wait_queue(&head,&data);
      sleep_on_timeout(&head,10);
      printk("<0>the current pid is:%d\n",current->pid);
      printk("<0>the state of the parent is:%ld\n",current->real_parent->state);
      complete(&comple);        //这里若不执行此函数,之前的wait_for_completioin便会一直堵死在那里
      printk("<0>out the kernel thread function\n");
      return 0;
 
     
static int __init wait_for_completion_init(void)
 
      int result;
      wait_queue_t data;
      printk("<0>into wait_for_completion_init.\n");                         
      result=kernel_thread(my_function, NULL, CLONE_KERNEL);
     
      struct pid * kpid=find_get_pid(result);
      struct task_struct * task=pid_task(kpid,PIDTYPE_PID);
      init_completion(&comple);      //初始化好变量,记得变量里还包含个:wait_queue_head_t
      init_waitqueue_entry(&data, task);
      __add_wait_queue_tail(&(comple.wait), &data);      //加入这个队列头
      wait_for_completion(&comple);      //等待,起到同步作用
      printk("<0>the result of the kernel_thread is :%d\n",result);
      printk("<0>the current pid is:%d\n",current->pid);
      printk("<0>out wait_for_completion_init.\n");
      return 0;
}
completion是同步用的,和等待队列放在一起,自然就露出了她的本来面目~
好了,就先说这么些。。。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值