Chinaunix首页 | 论坛 | 博客
  • 博客访问: 257354
  • 博文数量: 35
  • 博客积分: 883
  • 博客等级: 准尉
  • 技术积分: 656
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-17 09:38
文章分类

全部博文(35)

文章存档

2013年(1)

2012年(34)

分类: LINUX

2012-05-12 15:32:36

    上文说到小明驱车离开银行,随即开到了比较大的商城茂业(在深圳来说,茂业算是大商城咯)楼下,准备把车停在停车场下,进里面看看zippo火机,自己怎么也算是个“白骨精”(新时代对白领、骨干、精英的称谓),吸烟也得有个好装备:)驱车来到停车场前,发现保安在为排在前面的10辆车一个个的发停车卡,发停车卡很快的,自己等一下吧。不禁又联想到这个和操作系统的那个机制有些类似呢?对了,互斥锁。其实互斥锁和当count为1的信号量有相似之处,但却又不同。
信号量:count为1时,也可以达到互斥的效果,当进程想进入临界区的时候,首先获得信号量,当count为
        0时,进程进入睡眠状态,等待获得信号量的进程释放信号量。
互斥锁:专为互斥设计的,内部实现为:首先快速的的方式获得互斥锁,若是快速获得信号量
        失败,则进入通用的(慢速的)获取互斥锁,通用互斥锁获取方式同count为0时的机制相同。
从这里可以看到,互斥锁的一个设计原则是基于一个事实:拥有互斥锁的进程总是会在尽可能短的时间里释放。只有在这个前提下,使用互斥锁效率才是最高的,否则,和使用信号量差别也不大。对应到自己,发现自己在排队等待的过程多类似获得停车卡的一个过程,大家首先都认为发停车卡是一个很快的过程,所以,都排队等候而不会离开。当然,也有运气不好的,发到自己就发完了,没有停车位,那么你也可以选择停车等候,一旦有了停车位,保安会通知你让你进去。
互斥锁在内核中的定义如下:
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
};
去除调试信息后,我们发现和信号量的定义没有什么不同,主要差别体现在获取锁的操作DOWN和释放锁的操作UP上:
DOWN操作:
void __sched mutex_lock(struct mutex *lock)
{
 might_sleep();
 /*
  * The locking fastpath is the 1->0 transition from
  * 'unlocked' into 'locked' state.
  */
 __mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath);
 mutex_set_owner(lock);
}
UP操作:
void __sched mutex_unlock(struct mutex *lock)
{
 /*
  * The unlocking fastpath is the 0->1 transition from 'locked'
  * into 'unlocked' state:
  */
#ifndef CONFIG_DEBUG_MUTEXES
 /*
  * When debugging is enabled we must not clear the owner before time,
  * the slow path will always be taken, and that clears the owner field
  * after verifying that it was indeed current.
  */
 mutex_clear_owner(lock);
#endif
 __mutex_fastpath_unlock(&lock->count, __mutex_unlock_slowpath);
}
我们看红色和蓝色部分,一个是快速路径获取,一个是慢速路径获取,慢速路径获取没有什么可说的,现在我们重点说一下快速路径的获取:
static inline void
__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *))
{
 int __ex_flag, __res;
 __asm__ (
  "ldrex %0, [%2] \n\t"  //完成__res=count->counter
  "sub %0, %0, #1 \n\t"  //完成__res=__res - 1
  "strex %1, %0, [%2] "  //完成用_res的当前值来更新count->counter
  : "=&r" (__res), "=&r" (__ex_flag)
  : "r" (&(count)->counter)
  : "cc","memory" );
 __res |= __ex_flag;
 if (unlikely(__res != 0))
  fail_fn(count);
}
红色的ldrex和strex是ARM架构下实现“读-更新-写回”原子操作的方式,其原理也是在操作过程中对bus进行监控,x86上则是利用带有LOCK前缀的方式来实现总线的监控,从而达到原子操作的方式。up的实现类似,在此不累述。其实上面的原理很简单就可以对应到我们现实生活中,想想看:首先,保安从对讲机或电脑中获知车位的情况,然后,发给等待停车位的车辆以停车卡,最后,更新车位的数量。这个过程在我们现实过程中是没有问题的,是我们认为的保证这个过程是原子的;若哪天保安犯了糊涂,发给停车卡后,忘了更新停车位的数量,那么最终一定会出现一个停车位多个车在抢的情况。而对应到内核中,准确的说应当是计算机体系结构中,唯一可以控制对一块内存的并发性访问的要点就是控制总线,所以,不同架构产生了不同的控制总线的指令,但其目的是相同的。
    好了,让我们再次回到小明那里,小明今天的运气还不错,没等几分钟,就获得了停车卡,径直驶向停车场,下一次还会遇到哪些与内核中相似的机制呢?敬请期待。
 
阅读(2025) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~