向下之旅(十二):内核同步介绍
2016-03-21 15:19
141 查看
共享内存的应用程序必须特别留意保护共享资源,防止共享资源被并发的访问。内核也不例外。共享资源之所以要防止并发访问,是因为如果多个执行线程同时访问和操作数据,就有可能发生各线程之间相互覆盖共享数据的情况,造成被访问数据处于不一致状态。并发访问共享数据是造成系统不稳定的一类隐患。
临界区和竞争条件
临界区就是访问和操作共享数据的代码段。为了避免在临界区发生并发访问,编程者必须保证这些代码原子的执行——也就是说,代码在执行结束前不能被打断,如果两个执行线程有可能处于同一个临界区中,那么这就是程序包含的一个Bug。如果这种情况发生了,被称为竞争条件。避免并发和防止竞争条件被称为同步。
加锁
当出现并发线程访问共享数据的时候,此时需要给共享数据加锁,当获得锁的线程执行的时候,其他线程需等待,当线程执行完释放锁的时候,下一个线程获得锁,并重复执行上面任务。
锁的使用是自愿的,非强制的,它完全属于一种编程者自选的手段。没有什么可以强制编程者在操作我们虚构的队列时必须使用锁。当然,如果不这么做,无疑会造成竞争条件而破坏队列。
并发的产生
用户进程可能在任何时刻被抢占,而调度程序完全可能选择两一个高优先级的进程到处理器上执行,所以就有可能在一个程序正处于临界区时,就被非自愿的抢占了,如果新调度的程序随后也进入同一临界区,此时,前后两个进程相互之间就会产生竞争。这里其实想着并不真是同事发生的,但他们相互交叉进行,所以也可被称为伪并发执行。
如果是一个对称多处理机器,那么两个进程就可以真正的在临界区中同时进行了,这种类型被称为真并发。
内核中有类似可能造成并发执行的原因。它们是:
1.中断——中断几乎可以在任何时刻异步发生,也就可能随时打断当前正在执行的代码
2.软中断和tasklet——内核能在任何时候唤醒或调度软中断和tasklet,打断当前正在执行的代码
3.内核抢占——因为内核具有抢占性,所以内核中的任务可能会被另一任务抢占。
4.睡眠及用户空间的同步——在内核执行的进程可能会睡眠,这就会唤醒调度程序,从而导致调度一个新的用户进程执行
5.对称多处理——两个或多个处理器可以同时执行代码
死锁
死锁的产生需要一定的条件:要有一个或多个执行线程或一个或多个资源,每个线程都在等待其中一个资源,但所有的资源都已经被占用了。所有线程都在相互等待,但它们永远不会释放已经占有的资源。于是热河线程都无法继续,这便产生了死锁。
自死锁:一个线程视图去获得一个自己已经持有的锁,它将不得不等待锁被释放,但是却又不释放锁。
ABBA死锁
通过一些手段可预防死锁:
1.加锁的顺序是关键。使用嵌套的锁时必须保证以相同的顺序获取锁,这样可以阻止致命拥抱类型的锁。
2.防止发生饥饿
3.不要重复请求同一个锁
4.越复杂的加锁方案越有可能造成死锁——设计应求简单。
争用和扩展性
锁的争用,是指当锁正在被占用的时候,有其他的线程试图获得该锁。当一个锁处于高度争用的状态时,说明有多个线程在等在获得该锁。锁的使用会降低系统的性能。
扩展性是对系统可扩展程度的一个量度,对于操作系统,我们在谈及可扩展性的时候就会和大量的进程、处理器、或是大量的内存等联系起来。其实任何可以别计量的计算机组件都可以涉及可扩展性。
参考自:《Linux Kernel Development》.
临界区和竞争条件
临界区就是访问和操作共享数据的代码段。为了避免在临界区发生并发访问,编程者必须保证这些代码原子的执行——也就是说,代码在执行结束前不能被打断,如果两个执行线程有可能处于同一个临界区中,那么这就是程序包含的一个Bug。如果这种情况发生了,被称为竞争条件。避免并发和防止竞争条件被称为同步。
加锁
当出现并发线程访问共享数据的时候,此时需要给共享数据加锁,当获得锁的线程执行的时候,其他线程需等待,当线程执行完释放锁的时候,下一个线程获得锁,并重复执行上面任务。
锁的使用是自愿的,非强制的,它完全属于一种编程者自选的手段。没有什么可以强制编程者在操作我们虚构的队列时必须使用锁。当然,如果不这么做,无疑会造成竞争条件而破坏队列。
并发的产生
用户进程可能在任何时刻被抢占,而调度程序完全可能选择两一个高优先级的进程到处理器上执行,所以就有可能在一个程序正处于临界区时,就被非自愿的抢占了,如果新调度的程序随后也进入同一临界区,此时,前后两个进程相互之间就会产生竞争。这里其实想着并不真是同事发生的,但他们相互交叉进行,所以也可被称为伪并发执行。
如果是一个对称多处理机器,那么两个进程就可以真正的在临界区中同时进行了,这种类型被称为真并发。
内核中有类似可能造成并发执行的原因。它们是:
1.中断——中断几乎可以在任何时刻异步发生,也就可能随时打断当前正在执行的代码
2.软中断和tasklet——内核能在任何时候唤醒或调度软中断和tasklet,打断当前正在执行的代码
3.内核抢占——因为内核具有抢占性,所以内核中的任务可能会被另一任务抢占。
4.睡眠及用户空间的同步——在内核执行的进程可能会睡眠,这就会唤醒调度程序,从而导致调度一个新的用户进程执行
5.对称多处理——两个或多个处理器可以同时执行代码
死锁
死锁的产生需要一定的条件:要有一个或多个执行线程或一个或多个资源,每个线程都在等待其中一个资源,但所有的资源都已经被占用了。所有线程都在相互等待,但它们永远不会释放已经占有的资源。于是热河线程都无法继续,这便产生了死锁。
自死锁:一个线程视图去获得一个自己已经持有的锁,它将不得不等待锁被释放,但是却又不释放锁。
ABBA死锁
通过一些手段可预防死锁:
1.加锁的顺序是关键。使用嵌套的锁时必须保证以相同的顺序获取锁,这样可以阻止致命拥抱类型的锁。
2.防止发生饥饿
3.不要重复请求同一个锁
4.越复杂的加锁方案越有可能造成死锁——设计应求简单。
争用和扩展性
锁的争用,是指当锁正在被占用的时候,有其他的线程试图获得该锁。当一个锁处于高度争用的状态时,说明有多个线程在等在获得该锁。锁的使用会降低系统的性能。
扩展性是对系统可扩展程度的一个量度,对于操作系统,我们在谈及可扩展性的时候就会和大量的进程、处理器、或是大量的内存等联系起来。其实任何可以别计量的计算机组件都可以涉及可扩展性。
参考自:《Linux Kernel Development》.
相关文章推荐
- 深入理解ThreadLocal(二)
- 有关结对编程的感想
- VS快捷键
- Android动画分类和详解
- Scala之高阶函数
- expect的安装
- Ubuntu 系统中设置环境变量 PATH 的方法
- 《CLR Via C#》使用CSC.exe进行单文件的编译
- Zookeeper学习(十一):ZooKeeper 实现命名服务
- Google cardBoard Android API (十):HeadMountedDisplay
- java基础经典练习题
- 关于UIMenuController的用法例子
- java线程研究
- Android学习之解决ScrollView嵌套ListView显示的错误
- webview加载html格式的文本出现乱码
- 作业:用HTML制作邮箱登陆界面
- 批处理学习:for语句详解【经典】(转)
- iOS证书失效
- 【Codeforces Round 263 (Div 2)D】【树形DP】Appleman and Tree 树上割k个黑点为k块的方案数
- Gradle使用小结