Linux内核锁

在Linux内核里面,一般采用了如下几种锁的机制,来保证多线程的同步与互斥:

(1)原子操作

atomic_t v;
void atomic_set(atomic_t *v, int i);
atomic_t v = ATOMIC_INIT(0);
int atomic_read(atomic_t *v);
void atomic_add(int i, atomic_t *v);
void atomic_sub(int i, atomic_t *v);
void atomic_inc(atomic_t *v);
void atomic_dec(atomic_t *v);
void set_bit(nr, void *addr);
void clear_bit(nr, void *addr);
 

(2)自旋锁

不可递归

不可睡眠

中断上下文可使用

短期持有

spinlock_t my_lock = SPIN_LOCK_UNLOCKED;
void spin_lock_init(spinlock_t *lock);
 
void spin_lock(spinlock_t *lock);
void spin_unlock(spinlock_t *lock);
 

(3)信号量

允许睡眠

适合长期占有

只能在进程上下文使用

void sema_init(struct semaphore *sem, int val);
DEFINE_SEMAPHORE(name)
void down(struct semaphore *sem);
int down_interruptible(struct semaphore *sem);
int down_trylock(struct semaphore *sem);
void up(struct semaphore *sem);
 

(4)互斥体
void mutex_init(struct mutex *mutex); 
static DEFINE_MUTEX(mymutex);  
mutex_lock(&mymutex); 
/* Critical Section code ... */  
g_i++;
mutex_unlock(&mymutex);

int mutex_lock_interruptible(struct mutex *lock); 
int mutex_trylock(struct mutex *lock);  //never sleeps

(5)完成变量

//定义和初始化
struct completion my_completion; init_completion(&my_completion);
//等待
void wait_for_completion(struct completion *c);
//完成
void complete(struct completion *c);
void complete_all(struct completion *c); 

一个任务通知另外一个任务发生了某个特定的事件。同步两个任务。

(6)读写锁

rwlock_t my_rwlock = RW_LOCK_UNLOCKED; /* Static way */
rwlock_t my_rwlock;
rwlock_init(&my_rwlock); /* Dynamic way */
void read_lock(rwlock_t *lock);
void read_unlock(rwlock_t *lock);
void write_lock(rwlock_t *lock);
void write_unlock(rwlock_t *lock);

Linux软中断和工作队列

(1)中断处理程序局限:

异步方式执行并且可能会打断其他重要代码,甚至是其他中断处理程序

往往对硬件进行操作,需要很高的时限要求,效率要高,时间要少

中断上下文不能阻塞

一般只完成必要的数据拷贝

(2)下半部机制

下半部的任务是执行与中断处理密切相关但中断处理程序本身不执行的工作。在下半部运行时,可以响应所有的中断。

a.软中断

b.tasklet

c.工作队列

大多数时候选择tasklet;需要睡眠选择工作队列;执行频率和连续性高时选择软中断。

软中断:

a)产生后并不是马上可以执行,必须要等待内核的调度才能执行。软中断不能被自己打断,只能被硬件中断打断(上半部)。

b)可以并发运行在多个CPU上(即使同一类型的也可以)。所以软中断必须设计为可重入的函数(允许多个CPU同时操作),因此也需要使用自旋锁来保护其数据结构。

tasklet:

由于软中断必须使用可重入函数,这就导致设计上的复杂度变高,作为设备驱动程序的开发者来说,增加了负担。而如果某种应用并不需要在多个CPU上并行执行,那么软中断其实是没有必要的。因此诞生了弥补以上两个要求的tasklet。它具有以下特性:

a)一种特定类型的tasklet只能运行在一个CPU上,不能并行,只能串行执行。

b)多个不同类型的tasklet可以并行在多个CPU上。

c)软中断是静态分配的,在内核编译好之后,就不能改变。但tasklet就灵活许多,可以在运行时改变(比如添加模块时)。

workqueue:

软中断和tasklet运行在中断上下文中,于是导致了一些问题:不能睡眠、不能阻塞。由于中断上下文处于内核态,没有进程切换,所以如果软中断一旦睡眠或者阻塞,将无法退出这种状态,导致内核会整个僵死。但可阻塞函数不能用在中断上下文中实现,必须要运行在进程上下文中,例如访问磁盘数据块的函数。因此,可阻塞函数不能用软中断来实现。但是它们往往又具有可延迟的特性。

因此在2.6版的内核中出现了在内核态运行的工作队列(替代了2.4内核中的任务队列)。它也具有一些可延迟函数的特点(需要被激活和延后执行),但是能够能够在不同的进程间切换,以完成不同的工作。

上半部和下半部的区别
上半部指的是中断处理程序,下半部则指的是一些虽然与中断有相关性但是可以延后执行的任务。举个例子:在网络传输中,网卡接收到数据包这个事件不一定需要马上被处理,适合用下半部去实现;但是用户敲击键盘这样的事件就必须马上被响应,应该用中断实现。
两者的主要区别在于:中断不能被相同类型的中断打断,而下半部依然可以被中断打断;中断对于时间非常敏感,而下半部基本上都是一些可以延迟的工作。由于二者的这种区别,所以对于一个工作是放在上半部还是放在下半部去执行,可以参考下面四条:
a)如果一个任务对时间非常敏感,将其放在中断处理程序中执行。
b)如果一个任务和硬件相关,将其放在中断处理程序中执行。
c)如果一个任务要保证不被其他中断(特别是相同的中断)打断,将其放在中断处理程序中执行。

d)其他所有任务,考虑放在下半部去执行。

Linux内核工作在进程上下文或者中断上下文。提供系统调用服务的内核代码代表发起系统调用的应用程序运行在进程上下文,代表进程运行;另一方面,中断处理程序,异步运行在中断上下文,代表硬件运行,中断上下文和特定进程无关。运行在中断上下文的代码就要受一些限制,不能做下面的事情:

1、睡眠或者放弃CPU。(硬件与人睡眠例子)

因为内核在进入中断之前会关闭进程调度,一旦睡眠或者放弃CPU,这时内核无法调度别的进程来执行,系统就会死掉

2、尝试获得信号量

如果获得不到信号量,代码就会睡眠,效果同1

3、执行耗时的任务

中断处理应该尽可能快,因为内核要响应大量服务和请求,中断上下文占用CPU时间太长会严重影响系统功能。

4、访问用户空间的虚拟地址

Linux内核锁与中断处理的更多相关文章

  1. linux内核--中断和中断处理(一)

        让硬件在需要的时候再向内核发出信号.这就是中断机制,先讨论中断,进而讨论内核如何使用所谓的中断处理函数处理对应的中断. 一.中断   1)中断     中断使得硬件得以发出通知给处理器.例如, ...

  2. Linux内核中断处理机制

    <什么是中断> 计算停下当前处理任务,并保存现场,转而去处理其他是任务,当完成任务后再回到原来的任务中去. <中断的分类> a:软中断     软中断时执行中断指令产生的,软中 ...

  3. Linux内核中锁机制之RCU、大内核锁

    在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核锁(BKL).文章的最后对<大话Linu ...

  4. 大话Linux内核中锁机制之RCU、大内核锁

    大话Linux内核中锁机制之RCU.大内核锁 在上篇博文中笔者分析了关于完成量和互斥量的使用以及一些经典的问题,下面笔者将在本篇博文中重点分析有关RCU机制的相关内容以及介绍目前已被淘汰出内核的大内核 ...

  5. linux内核打印"BUG: scheduling while atomic

    linux内核打印"BUG: scheduling while atomic"和"bad: scheduling from the idle thread"错误 ...

  6. 十天学Linux内核之第六天---调度和内核同步

    原文:十天学Linux内核之第六天---调度和内核同步 心情大好,昨晚我们实验室老大和我们聊了好久,作为已经在实验室待了快两年的大三工科男来说,老师让我们不要成为那种技术狗,代码工,说多了都是泪啊,, ...

  7. 24小时学通Linux内核之调度和内核同步

    心情大好,昨晚我们实验室老大和我们聊了好久,作为已经在实验室待了快两年的大三工科男来说,老师让我们不要成为那种技术狗,代码工,说多了都是泪啊,,不过我们的激情依旧不变,老师帮我们组好了队伍,着手参加明 ...

  8. TCP/IP协议栈在Linux内核中的运行时序分析

    网络程序设计调研报告 TCP/IP协议栈在Linux内核中的运行时序分析 姓名:柴浩宇 学号:SA20225105 班级:软设1班 2021年1月 调研要求 在深入理解Linux内核任务调度(中断处理 ...

  9. LINUX内核笔记:自旋锁

    目录 自旋锁作用与基本使用方法? 在SMP和UP上的不同表现? 自旋锁与上下文 使用spin_lock()后为什么不能睡眠? 强调:锁什么? 参考   1.自旋锁作用与基本使用方法? 与其他锁一样,自 ...

随机推荐

  1. freebsd网卡驱动程序详解

    freebsd网卡驱动程序详解 来源 https://blog.csdn.net/h_cszc/article/details/7776116 /* 注释:xie_minix */ /*此处为BSD申 ...

  2. Password [分块]

    题面 $n,m,x \leq 10^5$ 思路 首先$n=2$做法很多,不讲了 $n=3$的时候,分块维护两个东西:每一个数出现次数的前缀和,和出现次数的出现次数的前缀和(说的有点绕,但是应该挺好理解 ...

  3. 2.1 Python3.5安装以及爬虫需要的环境配置

    之所以选用Python,是因为对于网络爬虫来说,Python是最好上手的一种语言.本文讲述的安装配置都是基于Windows的环境. 另外我想说的是,文中用到的下载链接尽量官方网站上的下载链接,这是我比 ...

  4. Linux命令之rhn_check

    NAME rhn_check - check for queued actions on RHN and execute them SYNOPSIS /usr/sbin/rhn_check [-v] ...

  5. 洛谷P1522 牛的旅行

    题目描述 农民 John的农场里有很多牧区.有的路径连接一些特定的牧区.一片所有连通的牧区称为一个牧场.但是就目前而言,你能看到至少有两个牧区通过任何路径都不连通.这样,Farmer John就有多个 ...

  6. PLSQL自动断开服务器连接 (转)

    最近,有同事反映在使用PLSQL连接数据库的时候,总是出现数据库频繁自动断开连接.这是因为资源配置文件中IDLE_TIME参数的限制,IDLE_TIME指定会话允许连续不活动的总的时间,以分钟为单位, ...

  7. c++ 实现 http 上传和下载

    代码下载地址:   http://download.csdn.net/detail/mtour/8243527 最近写了个程序需要用到http通讯,由于flash空间比较小,没有考虑 libcurl库 ...

  8. 获取URL中的文件的扩展名

    问题: 尽可能多地写出获取文件扩展名的方法: //方法一(分割数组) function getExt($url){ $arr = explode('.',$url); $len = count($ar ...

  9. 【linux高级程序设计】(第十一章)System V进程间通信 1

    System V, 曾经也被称为 AT&T System V,是Unix操作系统众多版本中的一支. 传统上,System V 被看作是两种UNIX"风味"之一(另一个是 B ...

  10. 【原创】配置Windows Live Writer,写cnblogs博客

    20180115更新补充: 现在live writer已经改名open live writer了,需要去下载的到地址:http://openlivewriter.org/ 引言 以前写博客一般都是联网 ...