linux内核同步

死锁:

死锁的产生需要一定的条件:要有一个或者多个执行线程和一个或者多个资源,每个线程都在等待其中一个资源,但所有的资源都已经别占用了,所有的线程都在相互等待,但他们永远不会释放已经占有的资源,于是任何线程都无法继续,这便意味着死锁的发生

死锁产生的条件:

1:资源不能被共享,只能由一个进程使用

2:请求与保持条件(Hold and wait)已经得到资源的进程可以再次申请新的资源

3:非剥夺条件(No Pre-emption)已经分配的资源不能被剥夺

4:循环等待(Circular Wait):系统中若干进程组成环路,该环路中的每个进程都在等待相邻进程使用的资源

大部分内容取自:http://www.ibm.com/developerworks/cn/linux/l-synch/part1/index.html

参考《linux内核设计与实现》

linux中的内核同步机制:

1:原子操作

所谓原子操作,就是该操作绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位,因此这里的原子实际是使用了物理学里的物质微粒的概念。

原子操作需要硬件的支持,因此是架构相关的,其API和原子类型的定义都定义在内核源码树的include/asm/atomic.h文件中,它们都使用汇编语言实现,因为C语言并不能实现这样的操作。

原子操作主要用于实现资源计数,很多引用计数(refcnt)就是通过原子操作实现的。

原子类型定义如下:


typedef struct { volatile int counter; } atomic_t;

volatile修饰字段告诉gcc不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问。

2:自旋锁:spin_lock

自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。由于自旋锁使用者一般保持锁时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋锁的效率远高于互斥锁。

自旋锁相当于坐在门外,等待同伴从房间里出来,并把钥匙交给你, 如果你到了门口发现房间里没人,就可以抓起钥匙进入,如果发现里边有人,就得在门外等待钥匙, 不断的检查房间是否为空。 钥匙就相当于自旋锁

有读写自旋锁,解决读写互斥问题 read_lock(),read_unlock(),write_lock(),write_unlock().

3:信号量

Linux内核的信号量在概念和原理上与用户态的System V的IPC机制信号量是一样的,但是它绝不可能在内核之外使用,因此它与System V的IPC机制信号量毫不相干。

信号量在创建时需要设置一个初始值,表示同时可以有几个任务可以访问该信号量保护的共享资源,初始值为1就变成互斥锁(Mutex),即同时只能有一个任务可以访问信号量保护的共享资源。一个任务要想访问共享资源,首先必须得到信号量,获取信号量的操作将把信号量的值减1,若当前信号量的值为负数,表明无法获得信号量,该任务必须挂起在该信号量的等待队列等待该信号量可用;若当前信号量的值为非负数,表示可以获得信号量,因而可以立刻访问被该信号量保护的共享资源。当任务访问完被信号量保护的共享资源后,必须释放信号量,释放信号量通过把信号量的值加1实现,如果信号量的值为非正数,表明有任务等待当前信号量,因此它也唤醒所有等待该信号量的任务。

与自旋锁的差别在于,等待的人不是在徘徊等待,而是把自己的名字写在等待表中,打盹去了,当房间里的人离开房间时,叫醒列表上第一个名字。这比自旋锁更好的利用了处理器的利用率,因为它没有把时间花在忙等待上,但是,信号量比自旋锁有了更大的开销。

读写信号量,对信号量进行了细分,要么读,要么写




posted @ 2012-03-26 10:22  foreverlearn  阅读(114)  评论(0编辑  收藏  举报