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)。
  • 前一章描述的关于按键中断处理存在竞态的问题是单独一个进程在多核情况下导致的,所以使用中断屏蔽没不能解决问题,所以中断屏蔽并不适用于多核导致的竞态问题。


相关文章
|
29天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
78 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
29天前
|
安全 Linux API
Linux设备模型统一:桥接硬件多样性与应用程序开发的关键
在Linux的宏大世界中,各种各样的硬件设备如星辰般繁多。从常见的USB设备到复杂的网络接口卡,从嵌入式设备到强大的服务器,Linux需要在这些差异极大的硬件上运行。这就引出了一个问题:Linux是如何统一这些不同硬件的设备模型的呢?本文将探讨Linux是如何针对不同的硬件统一设备模型的,这一统一的设备模型对于应用程序开发人员来说又有何意义。让我们一探究竟🕵️‍♂️。
Linux设备模型统一:桥接硬件多样性与应用程序开发的关键
|
29天前
|
Unix Linux Shell
FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
在Linux环境下交叉编译Android所需的FFmpeg so库,首先下载`android-ndk-r21e`,然后解压。接着,上传FFmpeg及相关库(如x264、freetype、lame)源码,修改相关sh文件,将`SYSTEM=windows-x86_64`改为`SYSTEM=linux-x86_64`并删除回车符。对x264的configure文件进行修改,然后编译x264。同样编译其他第三方库。设置环境变量`PKG_CONFIG_PATH`,最后在FFmpeg源码目录执行配置、编译和安装命令,生成的so文件复制到App工程指定目录。
63 9
FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
|
2天前
|
消息中间件 存储 监控
实战Linux I/O多路复用:借助epoll,单线程高效管理10,000+并发连接
本文介绍了如何使用Linux的I/O多路复用技术`epoll`来高效管理超过10,000个并发连接。`epoll`允许单线程监控大量文件描述符,显著提高了资源利用率。文章详细阐述了`epoll`的几个关键接口,包括`epoll_create`、`epoll_ctl`和`epoll_wait`,以及它们在处理并发连接中的作用。此外,还探讨了`epoll`在高并发TCP服务场景的应用,展示了如何通过`epoll`和线程/协程池来构建服务框架。
136 2
|
4天前
|
Web App开发 安全 Linux
FFmpeg开发笔记(二十六)Linux环境安装ZLMediaKit实现视频推流
《FFmpeg开发实战》书中介绍轻量级流媒体服务器MediaMTX,但其功能有限,不适合生产环境。推荐使用国产开源的ZLMediaKit,它支持多种流媒体协议和音视频编码标准。以下是华为欧拉系统下编译安装ZLMediaKit和FFmpeg的步骤,包括更新依赖、下载源码、配置、编译、安装以及启动MediaServer服务。此外,还提供了通过FFmpeg进行RTSP和RTMP推流,并使用VLC播放器拉流的示例。
19 3
FFmpeg开发笔记(二十六)Linux环境安装ZLMediaKit实现视频推流
|
5天前
|
编解码 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已启用。
15 1
FFmpeg开发笔记(二十五)Linux环境给FFmpeg集成libwebp
|
6天前
|
Linux 芯片
Linux 驱动开发基础知识——查询方式的按键驱动程序_编写框架(十三)
Linux 驱动开发基础知识——查询方式的按键驱动程序_编写框架(十三)
9 2
|
11天前
|
Linux 编解码 Python
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
AV1是一种高效免费的视频编码标准,由AOM联盟制定,相比H.265压缩率提升约27%。各大流媒体平台倾向使用AV1。本文介绍了如何在Linux环境下为FFmpeg集成AV1编解码库libaom、libdav1d和libsvtav1。涉及下载源码、配置、编译和安装步骤,包括设置环境变量以启用这三个库。
35 3
FFmpeg开发笔记(二十四)Linux环境给FFmpeg集成AV1的编解码器
|
24天前
|
运维 网络协议 Linux
2024年最全CentOS8 Consul微服务架构安装(1)_agent(1),Linux运维开发面试
2024年最全CentOS8 Consul微服务架构安装(1)_agent(1),Linux运维开发面试
|
25天前
|
编解码 Linux 5G
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
AVS3,中国制定的第三代音视频标准,是首个针对8K和5G的视频编码标准,相比AVS2和HEVC性能提升约30%。uavs3d是AVS3的解码器,支持8K/60P实时解码,且在各平台有优秀表现。要为FFmpeg集成AVS3解码器libuavs3d,需从GitHub下载最新源码,解压后配置、编译和安装。之后,重新配置FFmpeg,启用libuavs3d并编译安装,通过`ffmpeg -version`确认成功集成。
33 0
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器