Linux驱动开发——并发和竞态(中断屏蔽方式的使用②)

简介: Linux驱动开发——并发和竞态(中断屏蔽方式的使用②)

文章目录

解决竞态引起异常的方法之中断屏蔽

中断屏蔽的特点

中断屏蔽解决竞态引起的异常编程步骤

示例(保证led灯同一时刻只能有一个进程操作打开)


解决竞态引起异常的方法之中断屏蔽

中断屏蔽的特点

中断屏蔽能够解决进程与进程之间的抢占引起的异常(进程之间的抢占本身基于软中断实现),中断屏蔽能够解决中断和进程的抢占引起的异常,能够解决 中断和中断引起的异常。

但是中断屏蔽无法解决多核引起的异常。

注意:使用中断屏蔽保护的临界区的代码执行速度要越快越好,更不能进行休眠操作。因为Linux系统的很多机制都跟中断密切相关(tasklet、软件定时器、硬件定时器等),长时间屏蔽中断非常危险。


中断屏蔽解决竞态引起的异常编程步骤

  1. 找出代码中哪些是共享资源。
  2. 找出代码中哪些是临界区。
  3. 确定所保护的临界区中是否有休眠操作,如果有休眠操作则不能考虑中断屏蔽的方式,如果没有且没有多核参与竞态,则可以考虑使用中断屏蔽。
  4. 访问临界区之前屏蔽中断:
unsigned long flags;
local_irq_save(flags);//屏蔽中断,保存中断标志到flags(内核来完成)

  1. 正常访问临界区,此时不会有其他进程抢占、也不会有其他中断打断。
  2. 访问临界区之后,恢复中断。
local_irq_restore(flags);//恢复中断

  1. 屏蔽中断和恢复中断务必逻辑上成对使用。

示例(保证led灯同一时刻只能有一个进程操作打开)

使用全局变量open_cnt来记录当前操作使用设备者的个数,初始值为1,open之后先自减,判断是否不为0,保证同一时刻只能有一个进程在操作设备。(具体实现如下)


  • led_drv.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
//共享资源
static int open_cnt = 1; //记录LED打开的状态开关
static int led_open(struct inode *inode, 
                        struct file *file)
{
    unsigned long flags;
    //屏蔽中断
    local_irq_save(flags);
    //临界区
    if(--open_cnt != 0) {
        printk("设备已被打开!\n");
        open_cnt++;
        //恢复中断
        local_irq_restore(flags);
        return -EBUSY;//返回设备忙错误码
    }
    //恢复中断
    local_irq_restore(flags);
    printk("设备打开成功!\n");
    return 0; //open返回成功
}
static int led_close(struct inode *inode, 
                        struct file *file)
{
    unsigned long flags;
    //屏蔽中断
    local_irq_save(flags);
    //临界区
    open_cnt++;
    //恢复中断
    local_irq_restore(flags);
    return 0;
}
//定义初始化硬件操作接口对象
static struct file_operations led_fops = {
    .owner = THIS_MODULE,
    .open = led_open,
    .release = led_close
};
//定义初始化混杂设备对象
static struct miscdevice led_misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "myled",
    .fops = &led_fops
};
static int led_init(void)
{
    misc_register(&led_misc);
    return 0;
}
static void led_exit(void)
{
    misc_deregister(&led_misc);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");


  • led_test.c
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(void)
{
    int fd;
    fd = open("/dev/myled", O_RDWR);
    if (fd < 0) {
        printf("打开设备失败!\n");
        return -1;
    }
    sleep(100000000);
    close(fd);
    return 0;
}


  • Makefile
obj-m += led_drv.o
all:
  make -C /opt/kernel SUBDIRS=$(PWD) modules
clean:
  make -C /opt/kernel SUBDIRS=$(PWD) clean


  • 执行结果(先后台运行一个led_test程序,再尝试运行一个进程试一下):

20191231080044558.png

  • 可以看到,当后台运行了一个进程在使用设备的时候,再有一个进程尝试打开设备就会失败(: Device or resource busy)。
  • 前一章描述的关于按键中断处理存在竞态的问题是单独一个进程在多核情况下导致的,所以使用中断屏蔽没不能解决问题,所以中断屏蔽并不适用于多核导致的竞态问题。


相关文章
|
22天前
|
编解码 Linux
FFmpeg开发笔记(二十八)Linux环境给FFmpeg集成libxvid
XviD是开源的MPEG-4视频编解码器,曾与DivX一起用于早期MP4视频编码,但现在已被H.264取代。要集成XviD到Linux上的FFmpeg,首先下载源码,解压后配置并编译安装libxvid。接着,在FFmpeg源码目录中,重新配置FFmpeg以启用libxvid,然后编译并安装。成功后,通过`ffmpeg -version`检查是否启用libxvid。详细步骤包括下载、解压libxvid,使用`configure`和`make`命令安装,以及更新FFmpeg配置并安装。
38 2
FFmpeg开发笔记(二十八)Linux环境给FFmpeg集成libxvid
|
2天前
|
存储 网络协议 Ubuntu
【Linux开发实战指南】基于UDP协议的即时聊天室:快速构建登陆、聊天与退出功能
UDP 是一种无连接的、不可靠的传输层协议,位于IP协议之上。它提供了最基本的数据传输服务,不保证数据包的顺序、可靠到达或无重复。与TCP(传输控制协议)相比,UDP具有较低的传输延迟,因为省去了建立连接和确认接收等过程,适用于对实时性要求较高、但能容忍一定数据丢失的场景,如在线视频、语音通话、DNS查询等。 链表 链表是一种动态数据结构,用于存储一系列元素(节点),每个节点包含数据字段和指向下一个节点的引用(指针)。链表分为单向链表、双向链表和循环链表等类型。与数组相比,链表在插入和删除操作上更为高效,因为它不需要移动元素,只需修改节点间的指针即可。但访问链表中的元素不如数组直接,通常需要从
|
2天前
|
SQL 自然语言处理 网络协议
【Linux开发实战指南】基于TCP、进程数据结构与SQL数据库:构建在线云词典系统(含注册、登录、查询、历史记录管理功能及源码分享)
TCP(Transmission Control Protocol)连接是互联网上最常用的一种面向连接、可靠的、基于字节流的传输层通信协议。建立TCP连接需要经过著名的“三次握手”过程: 1. SYN(同步序列编号):客户端发送一个SYN包给服务器,并进入SYN_SEND状态,等待服务器确认。 2. SYN-ACK:服务器收到SYN包后,回应一个SYN-ACK(SYN+ACKnowledgment)包,告诉客户端其接收到了请求,并同意建立连接,此时服务器进入SYN_RECV状态。 3. ACK(确认字符):客户端收到服务器的SYN-ACK包后,发送一个ACK包给服务器,确认收到了服务器的确
|
28天前
|
Web App开发 安全 Linux
FFmpeg开发笔记(二十六)Linux环境安装ZLMediaKit实现视频推流
《FFmpeg开发实战》书中介绍轻量级流媒体服务器MediaMTX,但其功能有限,不适合生产环境。推荐使用国产开源的ZLMediaKit,它支持多种流媒体协议和音视频编码标准。以下是华为欧拉系统下编译安装ZLMediaKit和FFmpeg的步骤,包括更新依赖、下载源码、配置、编译、安装以及启动MediaServer服务。此外,还提供了通过FFmpeg进行RTSP和RTMP推流,并使用VLC播放器拉流的示例。
42 3
FFmpeg开发笔记(二十六)Linux环境安装ZLMediaKit实现视频推流
|
29天前
|
编解码 Linux
FFmpeg开发笔记(二十五)Linux环境给FFmpeg集成libwebp
《FFmpeg开发实战》书中指导如何在Linux环境下为FFmpeg集成libwebp以支持WebP图片编解码。首先,从GitHub下载libwebp源码,解压后通过`libtoolize`,`autogen.sh`,`configure`,`make -j4`和`make install`步骤安装。接着,在FFmpeg源码目录中重新配置并添加`--enable-libwebp`选项,然后进行`make clean`,`make -j4`和`make install`以编译安装FFmpeg。最后,验证FFmpeg版本信息确认libwebp已启用。
42 1
FFmpeg开发笔记(二十五)Linux环境给FFmpeg集成libwebp
|
1月前
|
Linux 编解码 Python
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
AV1是一种高效免费的视频编码标准,由AOM联盟制定,相比H.265压缩率提升约27%。各大流媒体平台倾向使用AV1。本文介绍了如何在Linux环境下为FFmpeg集成AV1编解码库libaom、libdav1d和libsvtav1。涉及下载源码、配置、编译和安装步骤,包括设置环境变量以启用这三个库。
55 3
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
|
26天前
|
消息中间件 存储 监控
实战Linux I/O多路复用:借助epoll,单线程高效管理10,000+并发连接
本文介绍了如何使用Linux的I/O多路复用技术`epoll`来高效管理超过10,000个并发连接。`epoll`允许单线程监控大量文件描述符,显著提高了资源利用率。文章详细阐述了`epoll`的几个关键接口,包括`epoll_create`、`epoll_ctl`和`epoll_wait`,以及它们在处理并发连接中的作用。此外,还探讨了`epoll`在高并发TCP服务场景的应用,展示了如何通过`epoll`和线程/协程池来构建服务框架。
171 3
|
23天前
|
Linux Windows 虚拟化
【Linux环境搭建实战手册】:打造高效开发空间的秘籍
【Linux环境搭建实战手册】:打造高效开发空间的秘籍
|
2天前
|
运维 监控 大数据
部署-Linux01,后端开发,运维开发,大数据开发,测试开发,后端软件,大数据系统,运维监控,测试程序,网页服务都要在Linux中进行部署
部署-Linux01,后端开发,运维开发,大数据开发,测试开发,后端软件,大数据系统,运维监控,测试程序,网页服务都要在Linux中进行部署
|
6天前
|
NoSQL Linux 开发工具
【linux】在linux操作系统下快速熟悉开发环境并上手开发工具——体验不一样的开发之旅
【linux】在linux操作系统下快速熟悉开发环境并上手开发工具——体验不一样的开发之旅