Linux内核中并发与竞争的处理方法:原子操作代码举例二

一.  简介

前面文章学习了Linux内核中处理并发与竞争的一种方法:原子操作,并编写代码说明原子操作中对整型变量的操作,文章地址如下:

Linux内核中并发与竞争的处理方法:原子操作代码举例一-CSDN博客

本文学习原子操作中,针对整型变量的原子操作的另一种代码实现。

实现效果:实现对 LED 这个设备的互斥访问,也就是一次只允许一个应用程序可以使用 LED 灯。

二.  原子操作的另一种代码实现

1. 准备工程代码

这里在前面 8_atomic工程代码的基础上,进行更改。通过 vscode软件打开 8_atomic工程代码。

主要在 atomic.c文件中添加原子操作,实现对Led灯的互斥访问。

这里所使用的关键的原子操作函数为:

int atomic_dec_and_test(atomic_t *v)

该函数对原子类型的变量v原子的减少1,并判断其结果是否是0,如果为0则返回真,否则返回假。

2. 对整型变量进行原子操作的代码实现
 

atomic.c驱动文件加入原子操作代码后,如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/atomic.h>#define  LED_OFF     0
#define  LED_ON      1
#define  GPIOLED_NAME  "gpioled"
#define  GPIOLED_CNT   1//Led设备结构体
struct gpio_led {dev_t devid;int major;int minor;struct cdev cdev;struct class* class;struct device* dev;struct device_node * dev_node;int gpio_number;atomic_t lock;  //原子操作//这里定义:1表示设备未使用,0表示设备已使用};struct gpio_led gpioled;static int gpioled_open(struct inode *inode, struct file *filp)
{   /*通过判断原子变量的值来检查 LED 有没有被别的应用使用 */if(!atomic_dec_and_test(&gpioled.lock)) //{atomic_inc(&gpioled.lock);  /*小于 0 的话就加 1,使其原子变量等于 0 */printk("gpioled.lock:%d\n", gpioled.lock.counter);return -EBUSY;}filp->private_data = &gpioled; /*设置私有数据 */return 0;
}static ssize_t gpioled_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{int ret = 0;char rx_buf[2] = {0};ret = copy_from_user(rx_buf, buf, count);if(ret != 0){printk("copy_from_user failed!\n");}if(rx_buf[0] == LED_ON){    //设置低电平,打开Ledgpio_set_value(gpioled.gpio_number, 0);  }else if(rx_buf[0] == LED_OFF){   //设置高电平,关闭Ledgpio_set_value(gpioled.gpio_number, 1);}return 0;
}static int gpioled_close(struct inode *inode, struct file *filp)
{struct gpio_led * dev = (struct gpio_led*)(filp->private_data);/* 关闭驱动文件的时候释放原子变量 */atomic_inc(&dev->lock);return 0;
}const struct file_operations gpioled_fops = {.owner = THIS_MODULE,.open = gpioled_open,.release = gpioled_close,.write = gpioled_write,
};/*驱动模块入口函数*/
static int __init gpioled_init(void)
{int ret = 0;/*原子变量的初始化:向原子变量写1 */atomic_set(&gpioled.lock, 1); /*1.注册设备号*/gpioled.major = 0;if(gpioled.major) //给出主设备号{gpioled.devid = MKDEV(gpioled.major, 0);ret = register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);  }else //未给设备号时,向Linux申请设备号{ret = alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);gpioled.major = MAJOR(gpioled.devid);gpioled.minor = MINOR(gpioled.devid);}printk("gpioled.major: %d\n", gpioled.major);printk("gpioled.minor: %d\n", gpioled.minor);if(ret < 0){printk("apply dev_number failed!\n");goto apply_devid_failed;}/*2.设备初始化 */gpioled.cdev.owner = THIS_MODULE;cdev_init(&gpioled.cdev, &gpioled_fops);ret = cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);if(ret < 0){printk("cdev_add failed\n");goto cdev_add_failed;}/*3.自动创建设备节点*/gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);if (IS_ERR(gpioled.class)) {ret = PTR_ERR(gpioled.class);goto class_create_failed;}gpioled.dev = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME);if (IS_ERR(gpioled.dev)) {ret = PTR_ERR(gpioled.dev);goto dev_create_failed;}	 /*读取设备节点*/gpioled.dev_node = of_find_node_by_path("/gpioled");if(NULL == gpioled.dev_node){printk("find dev_node failed!\n");goto read_devnode_failed;}/*获取Led所对应的GPIO的编号*/gpioled.gpio_number = of_get_named_gpio(gpioled.dev_node, "led-gpio", 0);if(gpioled.gpio_number < 0){printk("get_named_gpio failed!\n");goto read_devnode_failed;}/*申请GPIO管脚 */ret = gpio_request(gpioled.gpio_number, GPIOLED_NAME);if(ret != 0){printk("gpio_request failed!\n");goto read_devnode_failed;}/*设置GPIO为输出,设置为高电平,关闭Led */ret = gpio_direction_output(gpioled.gpio_number, 1);if(ret != 0){printk("gpio_direction_input failed!\n");goto set_gpio_input_failed;}return 0;set_gpio_input_failed:gpio_free(gpioled.gpio_number);
read_devnode_failed:device_destroy(gpioled.class, gpioled.devid);
dev_create_failed:class_destroy(gpioled.class);
class_create_failed:cdev_del(&gpioled.cdev);
cdev_add_failed:unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);
apply_devid_failed:return ret;
}/*驱动模块出口函数*/
static void __exit gpioled_exit(void)
{//关闭Led灯gpio_set_value(gpioled.gpio_number, 1);/*1. 删除设备*/cdev_del(&gpioled.cdev);/*2. 注销设备号*/unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);//3. 销毁设备device_destroy(gpioled.class, gpioled.devid);/*4. 销毁类*/class_destroy(gpioled.class);/*释放IO */gpio_free(gpioled.gpio_number);
}/*驱动入口与出口*/
module_init(gpioled_init);
module_exit(gpioled_exit);
MODULE_LICENSE("GPL");  //License
MODULE_AUTHOR("WeiWuXian"); //author

三.  编译驱动代码与测试

1.  编译驱动代码

通过 ubuntu终端进入 8_atomic工程目录下,对驱动代码进行编译:

wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/8_atomic$ make
make -C /home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/home/wangtian/zhengdian_Linux/Linux_Drivers/8_atomic modules
make[1]: 进入目录“/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga”CC [M]  /home/wangtian/zhengdian_Linux/Linux_Drivers/8_atomic/atomic.oBuilding modules, stage 2.MODPOST 1 modulesCC      /home/wangtian/zhengdian_Linux/Linux_Drivers/8_atomic/atomic.mod.oLD [M]  /home/wangtian/zhengdian_Linux/Linux_Drivers/8_atomic/atomic.ko
make[1]: 离开目录“/home/wangtian/zhengdian_Linux/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga”
wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/8_atomic$ sudo cp atomic.ko /home/wangtian/linux/nfs_File/rootfs/lib/modules/4.1.15/ -f
wangtian@wangtian-virtual-machine:~/zhengdian_Linux/Linux_Drivers/8_atomic$ 

可以看出,驱动模块编译通过。

2. 测试驱动模块

接下来就是对该驱动模块进行测试,确定原子操作是否已经实现对 Led灯的互斥访问。在开发板上经过测试,这里的驱动模块所添加的原子操作,已经实现了对 Led设备的互斥访问。

测试方法与之前一样,可以参考如下文章进行测试:

Led灯驱动添加原子操作后驱动程序测试-CSDN博客

关于对原子操作的驱动讲到这里。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/700827.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

流畅的Python(十二)-继承的优缺点

一、核心要义 1. 子类化内置类型的缺点 2.多重继承和方法解析顺序 二、代码示例 1. 子类化内置类型的缺点 #!/usr/bin/env python # -*- coding: utf-8 -*- # Time : 2024/2/24 7:29 # Author : Maple # File : 01-子类化内置类型的问题.py # Software: PyCharm fr…

数字化转型导师坚鹏:数据安全法解读与政府数字化转型

网络安全法、数据安全法、个人信息保护法解读与政府数字化转型 课程背景&#xff1a; 很多机构存在以下问题&#xff1a; 不清楚网络安全法、数据安全法、个人信息保护法立法背景&#xff1f; 不知道如何理解网络安全法、数据安全法、个人信息保护法政策&#xff1f; 不…

高级RAG:使用RAGAs + LlamaIndex进行RAG评估,包括原理、图和代码

原文地址&#xff1a;Using RAGAs LlamaIndex for RAG evaluation 2024 年 2 月 5 日 如果您已经为实际的业务系统开发了检索增强生成&#xff08;Retrieval Augmented Generation, RAG&#xff09;应用程序&#xff0c;那么您可能会关心它的有效性。换句话说&#xff0c;您…

Golin 弱口令/漏洞/扫描/等保/基线核查的快速安全检查小工具

下载地址&#xff1a; 链接&#xff1a;https://pan.quark.cn/s/db6afba6de1f 主要功能 主机存活探测、漏洞扫描、子域名扫描、端口扫描、各类服务数据库爆破、poc扫描、xss扫描、webtitle探测、web指纹识别、web敏感信息泄露、web目录浏览、web文件下载、等保安全风险问题风险…

小雉系统uefi安全启动支持(微软认证)

概述 从windows8开始,微软以安全为由使用uefi替换了传统的bios引导系统,并从2021年启新生产的硬件不再支持传统bios,导致基于传统bios制作的小雉系统无法启动运行&#xff1a; uefi的安全启动原理是主板使用内置的微软公钥校验grub2等引导程序(未经过微软签名的grub2无法…

【前端素材】推荐优质后台管理系统Start Admin平台模板(附源码)

一、需求分析 后台管理系统是一种用于管理网站、应用程序或系统的工具&#xff0c;它通常作为一个独立的后台界面存在&#xff0c;供管理员或特定用户使用。下面详细分析后台管理系统的定义和功能&#xff1a; 1. 定义 后台管理系统是一个用于管理和控制网站、应用程序或系统…

nios ii开发随笔

错误一&#xff1a; d:/intelfpga/17.1/nios2eds/bin/gnu/h-x86_64-mingw32/bin/../lib/gcc/nios2-elf/5.3.0/../../../../../H-x86_64-mingw32/nios2-elf/bin/ld.exe: test.elf section .text will not fit in region ram_oc_xzs d:/intelfpga/17.1/nios2eds/bin/gnu/h-x86_6…

关于Spring中管理Bean的杂谈

关于Spring中管理Bean的杂谈 1 filter、监听器,不能直接被spring容器管理2 Listener监听器不能被Spring管理3 使用EasyExcel的自定义监听器,可使用Spring容器 1 filter、监听器,不能直接被spring容器管理 1 spring更多的是管理我们自己的各种组件&#xff0c;filter之类的是交…

鸿蒙OS应用开发之显示图片组件6

前面学习了怎么样让图片合适的大小来显示出来,达到最佳的布局显示图片。现在来学习PixelMap图片显示。PixelMap图片是指图片解码后无压缩的位图,用于图片显示或图片处理。 由于PixelMap图片是一种无压缩的图片,比较适合图片处理,比如从网络上加载图片之后,再进行处理再显示…

STM32-启用蜂鸣器

目录 1 、电路构成及原理图 2、编写实现代码 main.c beep.c beep.h 3、代码讲解 4、 烧录到开发板调试、验证代码 5、检验效果 本人使用的是朗峰 STM32F103 系列开发板&#xff0c;此笔记基于这款开发板记录。 1 、电路构成及原理图 首先&#xff0c;通过朗峰 F1 开…

SpringBoot 3 新特性

目录 1. GraalVM2. 支持虚拟线程3. HTTP Interface 1. GraalVM 使用GraalVM将SpringBoot应用程序编译成本地可执行的镜像文件&#xff0c;可以显著提升启动速度、峰值性能以及减少内存应用。传统的应用都是编译成字节码&#xff0c;然后通过JVM解释并最终编译成机器码来运行&a…

ELK入门(二)- springboot整合ES

springboot整合elasticsearch 引用依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http…

TT语音×个推:流失预测准确率超90%,撬动存量增长个推GeTui 2024-02-23 09:50 浙江

当移动互联网进入存量时代&#xff0c;如何更高效地进行用户全生命周期管理、提升用户生命周期价值&#xff0c;变得尤为重要。TT语音是国内领先的兴趣社交平台&#xff0c;累计注册用户数高达数亿。为了进一步盘活存量用户价值&#xff0c;TT语音从2019年起便与个推合作&#…

Java-8函数式编程设计-Functional-Interface

Java 8函数式编程设计-Functional-Interface 我自己的理解&#xff0c;函数式编程对用户最大的价值是促使开发者养成模块化编程的习惯&#xff0c;代码可读性和维护性提高很多。 通过阅读JDK 8的 java.util.function 和 java.util.stream 包源码&#xff0c;意在理解Java的函数…

AcWing 872:最大公约数 ← 递归及非递归解法等

【题目来源】https://www.acwing.com/problem/content/874/【题目描述】 给定 n 对正整数 ai,bi&#xff0c;请你求出每对数的最大公约数。【输入格式】 第一行包含整数 n。 接下来 n 行&#xff0c;每行包含一个整数对 ai,bi。【输出格式】 输出共 n 行&#xff0c;每行输出一…

三分钟快速搭建家纺行业小程序商城:轻松实现电子商务梦想

随着互联网的普及和移动设备的广泛使用&#xff0c;越来越多的商业活动正在向数字化转型。在这个过程中&#xff0c;小程序商城作为一种新型的电子商务模式&#xff0c;正逐渐受到商家的青睐。本文将通过具体步骤&#xff0c;指导读者如何开发一个纺织辅料小程序商城。 一、选择…

使用c++filt 还原RTTI返回的类型名称

考虑下面的代码 const char ori[] "feelling good"; auto copy ori; std::cout << typeid(ori).name() << \n; std::cout << typeid(copy).name() << \n; 在g 编译后输出 A14_c PKc typeid操作符会返回一个const type_info&对象&a…

EarMaster Pro 7 简体中文破解版下载 v7.2.0.42 电脑版

软件介绍 EarMaster Pro 简体中文破解版是一款由丹麦皇家音乐学院官方制作的多功能音乐品鉴教育软件&#xff0c;软件具有丰富的功能&#xff0c;它可以自定义培训课程&#xff0c;针对性地训练音准、节奏、和声等音乐要素&#xff0c;用户可以根据自身需求和水平选择不同难度…

【探索Linux】—— 强大的命令行工具 P.23(线程池 —— 简单模拟)

阅读导航 引言一、线程池简单介绍二、Linux下线程池代码⭕Makefile文件⭕ . h 头文件✅Task.hpp✅thread.hpp✅threadPool.hpp ⭕ . cpp 文件✅testMain.cpp 三、线程池的优点温馨提示 引言 在Linux下&#xff0c;线程池是一种常见的并发编程模型&#xff0c;它能够有效地管理…

代码随想录算法训练营(动态规划2)| 62.不同路径 63. 不同路径 II

62.不同路径 本题大家掌握动态规划的方法就可以。 数论方法 有点非主流&#xff0c;很难想到。 leetcode题目链接 题目链接/文章讲解 视频讲解 二叉树的深度搜索&#xff0c;找到总共有几个叶子节点 这个想理解好难啊 //每个节点都是从左向右&#xff0c;然后回溯&#xff0c…