在使用共享内存的应用程序中,程序员必须特别留意保护共享资源,防止共享资源并发访问。

一、临界区和竞争条件

1.1 临界区和竞争条件

所谓临界区就是访问和操作共享数据代码段。多个执行线程并发访问同一个资源通常是不安全的,为了避免在临界区中并发访问,编程者必须保证这些代码原子地执行。

如果两个执行线程有可能处于同一个临界区中同时执行,如果这种情况确实发生了,我们就称它是竞争条件。因为竞争引起的错误非常不易重现,所以调试这种错误才会非常困难。

避免并发和防止竞争条件称为同步。

为什么要保护?

有些事务必须完整地发生,要么干脆不发生,但是绝不能打断。

二、加锁

锁提供的就是这种机制:它就如同一把门锁,门后的房间可想象成要给临界区。在一个指定的时间内,房间里只能有一个执行线程存在,当一个线程进入房间后,它会锁住身后的房门。当它结束对共享数据的操作后,就会走出房间,打开门锁。如果另一个线程在房门上锁时来了,那么它就必须等待房间内的线程出来并发开门锁后,才能进入房间。

线程持有锁,锁保护了数据。

2.1 造成并发执行的原因

内核中有类似可能造成并发执行的原因,它们是:

  • 中断----中断几乎可以在任何时刻异步发生,也就可能随时打断当前正在执行的代码
  • 软中断和tasklet----内核能在任何时刻唤醒或调度软中断和tasklet,打断当前正在执行的代码
  • 内核抢占----因为内核具有抢占型,所以内核中的任务可能会被另一任务抢占
  • 睡眠及与用户空间的同步----在内核执行的进程可能会睡眠,这就会唤醒调度程序,从而导致调度一个新的用户进程执行
  • 对称多处理----两个或多个处理器可以同时执行代码

真正困难的就是发现上述的潜在并发执行的可能,并有意识地采取某些措施来防止并发执行。

其实,真正用锁来保护共享资源并不困难,尤其是在设计代码的早期就这么做了,事情就更简单了。

辨认出真正需要共享的数据和响应的临界区,才是真正有挑战性的地方。

2.2 了解要保护些什么

找出哪些数据需要保护是关键所在。

线程中的局部数据仅仅被它访问,显然不需要保护。还有动态分配的数据结构,其地址在堆栈中。也不需要

大多数内核数据结构都需要加锁,

如果有其他执行线程可以访问这些数据,那么就给这些数据加上某种形式的锁。

如果任何其他什么东西都能看到它,那么就要锁住它。记住:要给数据而不是给代码加锁。

在编写代码时,你要问自己下面这些问题:

  • 这个数据是不是全局的?除了当前线程外,其他线程能不能访问它。
  • 这个数据会不会在进程上下文和中断上下文中共享?它是不是要在两个不同的中断处理程序中共享?
  • 进程在访问数据时可不可能被抢占?被调度的新程序会不会访问同一数据?
  • 当前进程是不是会睡眠(阻塞)在某些资源上,如果是,它会让共享数据处于核中状态?
  • 怎样防止数据失控?
  • 如果这个函数又在另一个处理器上被调度将会发生什么呢?
  • 如何确保代码原理并发威胁呢?

简而言之,所有内核全局变量和共享数据都需要某种形式的同步方法。

三、死锁

死锁产生需要一定条件:要有一个或多个执行线程和一个或多个资源,每个线程都在等待其中的一个资源,但所有资源都已经被占用了。

自死锁:一个执行线程试图去获得要给自己已经持有的锁,它将不得不等待锁被释放。最后智能死锁

一些简单的规则对避免死锁大有帮助:

  • 按顺序加锁,使用嵌套的锁时必须保证以相同的顺序获取锁,这样可以阻止致命拥抱类型的死锁。最好能记录下锁的顺序,以便其他人也能照此顺序使用
  • 防止发饥饿,这个代码是不是一定能执行结束?如果张不发生,王是否要一直等待下去
  • 不要重复请求同一个锁
  • 设计应力求简单----越复杂的加锁方案越有可能死锁

防止死锁很重要,内核提供了一些简单易用的调试工具,可以在运行时检测死锁。

四、争用和扩展性

锁的争用,简称争用,指当锁正在被占用时,有其他线程试图获得该锁。

当一个锁处于高度争用状态,会成为系统的瓶颈。尽管如此,也比多个进程抢夺资源要好。

锁的粒度,需要合理的安排。很多锁的设计在开始阶段都很粗,但是当锁争用问题严重时,设计就向更加精细的加锁方向进化。

Linux内核设计与实现 总结笔记(第九章)内核同步介绍的更多相关文章

  1. Linux内核设计与实现——读书笔记1:内核简介

    内核:有的时候被称管理者或者操作系统核心,通常内核负责响应中断的中断服务程序, 负责管理多个进程从而分享处理器时间的调度程序,负责管理进程地址空间德内存管理程序 和网络,进程间通信等系统服务程序共同组 ...

  2. Linux内核设计与实现 读书笔记 转

    Linux内核设计与实现  读书笔记: http://www.cnblogs.com/wang_yb/tag/linux-kernel/ <深入理解LINUX内存管理> http://bl ...

  3. Linux内核设计与实现 读书笔记

    第三章 进程管理 1. fork系统调用从内核返回两次: 一次返回到子进程,一次返回到父进程 2. task_struct结构是用slab分配器分配的,2.6以前的是放在内核栈的栈底的:所有进程的ta ...

  4. 《Linux内核设计与实现》 第一二章学习笔记

    <Linux内核设计与实现> 第一二章学习笔记 第一章 Linux内核简介 1.1 Unix的历史 Unix的特点 Unix很简洁,所提供的系统调用都有很明确的设计目的. Unix中一切皆 ...

  5. 《Linux内核设计与实现》第四章学习笔记

    <Linux内核设计与实现>第四章学习笔记           ——进程调度 姓名:王玮怡  学号:20135116 一.多任务 1.多任务操作系统的含义 多任务操作系统就是能同时并发地交 ...

  6. 《Linux内核设计与实现》第五章学习笔记

    <Linux内核设计与实现>第五章学习笔记 姓名:王玮怡  学号:20135116 一.与内核通信     在Linux中,系统调用是用户空间访问内核的唯一手段:除异常和陷入外,它们是内核 ...

  7. 《Linux内核设计与分析》第四章读书笔记

    <内核设计与实现>第四章读书笔记 第四章:进程调度 进程(操作系统)程序的运行态表现形式. 进程调度程序,它是确保进程能有效工作的一个内核子系统. 调度程序负责决定将哪个进程投入运行,何时 ...

  8. 《Linux内核设计与实现》第四章学习笔记——进程调度

                                                                        <Linux内核设计与实现>第四章学习笔记——进程调 ...

  9. Android群英传笔记——第九章:Android系统信息和安全机制

    Android群英传笔记--第九章:Android系统信息和安全机制 本书也正式的进入尾声了,在android的世界了,不同的软件,硬件信息就像一个国家的经济水平,军事水平,不同的配置参数,代表着一个 ...

  10. 《Linux/UNIX系统编程手册》第56章 SOCKET:介绍

    关键词: 1. socket基础 一个典型的客户端/服务器场景中,应用程序使用socket进行通信的方式如下: 各个应用程序创建一个socket.socket是一个允许通信的设备,两个应用程序都需要用 ...

随机推荐

  1. linux常用终端指令+如何用vim写一个c程序并运行

    在装好ubuntu之后今天学习了一些linux的一些基础知识: windows里面打开命令窗口是win+r,在linux系统里面,ctrl+alt+t打开终端,今天的一些指令都是围绕终端来说的 首先s ...

  2. Python3 多线程编程 threading模块

    性能自动化测试除了用jmeter还可以用python threading模块做 一.threading模块定义 Python 2.4中包含的较新的线程模块为线程提供了更强大的高级支持. 线程模块公开线 ...

  3. 获取win10壁纸

    执行命令会将所有壁纸拷贝到桌面上的wallpaper文件夹内 bat xcopy %LOCALAPPDATA%\Packages\Microsoft.Windows.ContentDeliveryMa ...

  4. 初学node.js-nodejs中实现用户登录路由

    经过前面几次的学习,已经可以做下小功能,今天要实现的事用户登录路由. 一.users_model.js  功能:定义用户对象模型 var mongoose=require('mongoose'), S ...

  5. 修改SpringBoot启动时的默认Banner图案

    1.在src/main/resources下新建banner.txt,在文件中加入要显示的图案即可: 2.生成图案的网站: http://patorjk.com/software/taag/ http ...

  6. Hibernate 日期映射 条件查询

    1. hql: ...and accopt_time > ?" 2. query.setDate Query query = session.createQuery(hql); int ...

  7. NOIP提高组初赛难题总结

    NOIP提高组初赛难题总结 注:笔者开始写本文章时noip初赛新题型还未公布,故会含有一些比较老的内容,敬请谅解. 约定: 若无特殊说明,本文中未知数均为整数 [表达式] 表示:在表达式成立时它的值为 ...

  8. 如何将一个.NET Core类库发布到NuGet

    包治百病 | 如何将一个.NET Core类库发布到NuGet 写文章 包治百病 | 如何将一个.NET Core类库发布到NuGet Edi Wang发表于汪宇杰博客订阅 77 NuGet是.NET ...

  9. vue 防抖和节流

    函数防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时. 函数节流(throttle):当持续触 ...

  10. CollectionView刷新问题,以及定时器与控制器的销毁问题

    1.CollectionView的刷新必须首先保证CollectionView有高度 注意事项:在cell中嵌套CollectionView,如果使用的是AutoLayout的话,一定要注意保证Col ...