存在共享资源(共享一个文件,一块内存等等)的时候,为了防止并发访问时共享资源的数据不一致,引入了同步机制。

主要内容:

  1. 同步的概念
  2. 同步的方法-加锁
  3. 死锁
  4. 锁的粒度

1. 同步的概念

了解同步之前,先了解另外2个概念:

  • 临界区   - 也称为临界段,就是访问和操作共享数据的代码段。
  • 竞争条件 - 2个或2个以上线程在临界区里同时执行的时候,就构成了竞争条件。

所谓同步,其实防止在临界区中形成竞争条件。

如果临界区里是原子操作(即整个操作完成前不会被打断),那么自然就不会出竞争条件。

但在实际应用中,临界区中的代码往往不会那么简单,所以为了保持同步,引入了锁机制。

2. 同步的方法-加锁

为了给临界区加锁,保证临界区数据的同步,首先了解一下内核中哪些情况下会产生并发。

内核中造成竞争条件的原因:

竞争原因

说明

中断 中断随时会发生,也就会随时打断当前执行的代码。如果中断和被打断的代码在相同的临界区,就产生了竞争条件
软中断和tasklet 软中断和tasklet也会随时被内核唤醒执行,也会像中断一样打断正在执行的代码
内核抢占 内核具有抢占性,发生抢占时,如果抢占的线程和被抢占的线程在相同的临界区,就产生了竞争条件
睡眠及用户空间的同步 用户进程睡眠后,调度程序会唤醒一个新的用户进程,新的用户进程和睡眠的进程可能在同一个临界区中
对称多处理 2个或多个处理器可以同时执行相同的代码

为了在编写内核代码时避免出现竞争条件,在编写代码之前就要考虑好临界区在哪,以及怎么加锁

在编写完代码后再加锁是非常困难的,很可能还会导致部分代码重写。

编写内核代码时,时时记着下面这些问题:

  1. 这个数据是不是全局的?除了当前线程以外,其他线程能不能访问它?
  2. 这个数据会不会在进程上下文或者中断上下文中共享?它是不是要在两个不同的中断处理程序中共享?
  3. 进程在访问数据时可不可能被抢占?被调度的新程序会不会访问同一数据?
  4. 当前进程会不会睡眠(或者阻塞)在某些资源上,如果是,它会让共享数据处于何种状态?
  5. 怎样防止数据失控?
  6. 如果这个函数又在另一个处理器上被调度将会发生什么?

3. 死锁

死锁就是所有线程都在相互等待释放资源,导致谁也无法继续执行下去。

下面一些简单的规则可以帮助我们避免死锁:

  1. 如果有多个锁的话,尽量确保每个线程都是按相同的顺序加锁,按加锁相反的顺序解锁。(即加锁a->b->c,解锁c->b->a)
  2. 防止发生饥饿。即设置一个超时时间,防止一直等待下去。
  3. 不要重复请求同一个锁。
  4. 设计应力求简单。加锁的方案越复杂就越容易出现死锁。

4. 锁的粒度

在加锁的时候,不仅要避免死锁,还需要考虑加锁的粒度。

锁的粒度对系统的可扩展性有很大影响,在加锁的时候,要考虑一下这个锁是否会被多个线程频繁的争用。

如果锁有可能会被频繁争用,就需要将锁的粒度细化。

细化后的锁在多处理器的情况下,性能会有所提升。

举个例子说明一下:比如给一个链表加锁,同时有A,B,C 3个线程频繁访问这个链表。

那么当A,B,C 3个线程同时访问这个链表时,如果A获得了锁,那么B,C线程只能等待A释放了锁后才能访问这个链表。

如果A,B,C 3个线程访问的是这个链表的不同节点(比如A是修改节点listA,B是删除节点listB,C是追加节点listC),

并且这3个节点不是连续的,那么3个线程同时运行是不会有问题的。

这种情况下就可以细化这个锁,把加在链表上的锁去掉,改成把锁加在链表的每个节点上。(也就是锁粒度的细化)

那么,上述的情况下,A,B,C 3个线程就可以同时访问各自的节点,特别是在多处理器的情况下,性能会有显著提高。

最后还有一点需要提醒的是,锁的粒度越细,系统开销越大,程序也越复杂,所以对于争用不是很频繁的锁,就没有必要细化了。

《Linux内核设计与实现》读书笔记(九)- 内核同步介绍的更多相关文章

  1. Linux内核设计与实现读书笔记(8)-内核同步方法【转】

    转自:http://blog.chinaunix.net/uid-10469829-id-2953001.html 1.原子操作可以保证指令以原子的方式执行——执行过程不被打断.内核提供了两组原子操作 ...

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

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

  3. Linux内核设计与实现——读书笔记2:进程管理

    1.进程: (1)处于执行期的程序,但不止是代码,还包括各种程序运行时所需的资源,实际上进程是正在执行的 程序的实时结果. (2)程序的本身并不是进程,进程是处于执行期的程序及其相关资源的总称. (3 ...

  4. 《Linux内核设计与实现》笔记-1-linux内核简单介绍

    一.Linux内核相对于传统的UNIX内核的比較: (1):Linux支持动态内核模块. 虽然Linux内核也是总体式结构,但是同意在须要的时候动态哦卸除(rmmod xxx)和载入内核模块(insm ...

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

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

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

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

  7. Linux Shell脚本攻略 读书笔记

    Linux Shell脚本攻略 读书笔记 这是一本小书,总共253页,但内容却很丰富,书中的示例小巧而实用,对我这样总是在shell门前徘徊的人来说真是如获至宝:最有价值的当属文本处理,对这块我单独整 ...

  8. 【2018.08.13 C与C++基础】C++语言的设计与演化读书笔记

    先占坑 老实说看这本书的时候,有很多地方都很迷糊,但却说不清楚问题到底在哪里,只能和Effective C++联系起来,更深层次的东西就想不到了. 链接: https://blog.csdn.net/ ...

  9. 《Linux内核分析与设计实现》读书笔记一

    第一章 Linux内核简介 1.1 Unix的历史 Unix的特点: Unix很简洁,仅仅提供几百个系统调用并且有一个非常明确的设计目的: 在Unix中,所有的东西都被当做文件对待. Unix的内核和 ...

  10. 初探内核之《Linux内核设计与实现》笔记上

    内核简介  本篇简单介绍内核相关的基本概念. 主要内容: 单内核和微内核 内核版本号 1. 单内核和微内核   原理 优势 劣势 单内核 整个内核都在一个大内核地址空间上运行. 1. 简单.2. 高效 ...

随机推荐

  1. Kosaraju

    https://www.cnblogs.com/nullzx/p/6437926.html

  2. 浅析TCP /UDP/ IP协议

    互连网早期的时候,主机间的互连使用的是NCP协议.这种协议本身有很多缺陷,如:不能互连不同的主机,不能互连不同的操作系统,没有纠错功能.为了改善这种缺点,大牛弄出了TCP/IP协议.现在几乎所有的操作 ...

  3. VI与VIM区别

    Vim是从 vi 发展出来的一个文本编辑器 .代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用.和Emacs 并列成为类Unix系统 用户最喜欢的编辑器. Vim的第一个版本由B ...

  4. DCloud:temple

    ylbtech-DCloud: 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返回顶部   8.返回顶部   9.返回顶部   1 ...

  5. UML关系说明文档

    http://blog.csdn.net/suxinpingtao51/article/details/8011335/

  6. 问题:Custom tool error: Failed to generate code for the service reference 'AppVot;结果:添加Service Reference, 无法为服务生成代码错误的解决办法

    添加Service Reference, 无法为服务生成代码错误的解决办法 我的解决方案是Silverlight+WCF的应用,Done Cretiria定义了需要在做完Service端的代码后首先运 ...

  7. VS2015 MSVC编译FFMPEG

    1.下载安装msys2 http://www.msys2.org/下载msys2 下载安装完成后,在msys2的shell中安装编译FFMPEG必要的命令行工具 pacman -S make gcc ...

  8. C语言学习笔记--#error 、 #line 和 #pragma 的使用

    1. #error 的用法 (1)#error 是一种预编译器指示字,用于生成一个编译错误消息 (2)用法:#error message //注意:message 不需要用双引号包围 (3)#erro ...

  9. DAY13-前端之jQuery

    jQuery jQuery介绍 jQuery是一个轻量级的.兼容多浏览器的JavaScript库. jQuery使用户能够更方便地处理HTML Document.Events.实现动画效果.方便地进行 ...

  10. 使用百度地图SDK 这是之前版本 现在的sdk v2-1-2使用方法完全改变

    1.添加BMapApiDemoApp.java 2.AndroidManifest文件  application里添加  android:name=".ui.BMapApiDemoApp&q ...