Linux驱动开发笔记(六)中断子系统及实验

news2024/11/18 16:30:13

文章目录

  • 前言
  • 一、中断子系统框架
    • 1. 中断硬件简单描述
    • 2. 中断的软件描述
      • 2.1 中断处理的两部分模型
      • 2.2 系统框架
  • 二、GIC v3中断控制器
    • 1. GIC v3基本结构
      • 1.1 Distributor
      • 1.2 Redistributor
      • 1.3 ITS
      • 1.4 CPU interface
    • 2. 中断类型与特点
    • 3. 中断号
  • 三、函数编写
    • 3.1 相关API函数
    • 3.2 驱动初始化函数
    • 3.3 operations函数
      • 3.3.1 open函数
      • 3.3.2 .read
      • 3.3.3 .release
    • 3.4 中断函数
  • 四、设备树的编辑
    • 1. 设备树插件格式
    • 2. 设备树插件的编写


前言

  本章我们将讲解下和中断相关的知识,了解内核中断的框架和中断的概念,对于arm的中断控制器(GIC v3)相关内容,主要是借鉴参考手册简单解释下。


一、中断子系统框架

  Linux中的中断相似于之前STM32的中断,是硬件在需要时向CPU发出的一种信号,导致CPU暂时停止当前正在执行的程序,转而处理这个硬件请求的一种机制。
  中断发生在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的CPU暂时停止正在运行的程序,转而去为该内部或外部事件或预先安排的事件服务,服务完毕后再返回继续执行原来的程序。

1. 中断硬件简单描述

  中断硬件主要有三种器件参与,各个外设、中断控制器和CPU。之间的关系可以简单看下下面图片:
在这里插入图片描述

2. 中断的软件描述

2.1 中断处理的两部分模型

  上半部(Top Half):在接收到中断后立即执行,完成一些必要的工作(如应答、复位等)。这部分工作有严格的时间限制,需要尽快完成。
  底半部(Bottom Half):在合适的时机执行,完成可以被推迟到后面完成的任务。底半部通常用于执行一些耗时的操作,以避免在中断处理过程中阻塞其他中断的响应。

2.2 系统框架

  一个完整的中断子系统框架可以分为四个层次,由上到下分别为用户层、通用层、硬件相关层和硬件层,每个层相关的介绍如下所示:

  • 用户层:用户层是中断的使用者,主要包括各类设备驱动。这些驱动程序通过中断相关的接口进行中断的申请和注册。当外设触发中断时,用户层驱动程序会进行相应的回调处理,执行特定的操作。
  • 通用层:通用层也可称为框架层,它是硬件无关的层次。通用层的代码在所有硬件平台上都是通用的,不依赖于具体的硬件架构或中断控制器。通用层提供了统一的接口和功能,用于管理和处理中断,使得驱动程序能够在不同的硬件平台上复用。
  • 硬件相关层:硬件相关层包含两部分代码。一部分是与特定处理器架构相关的代码,比如ARM64处理器的中断处理相关代码。这些代码负责处理特定架构的中断机制,包括中断向量表、中断处理程序等。另一部分是中断控制器的驱动代码,用于与中断控制器进行通信和配置。这些代码与具体的中断控制器硬件相关。
  • 硬件层:硬件层位于最底层,与具体的硬件连接相关。它包括外设与SoC(系统片上芯片)的物理连接部分。中断信号从外设传递到中断控制器,由中断控制器统一管理和路由到处理器。硬件层的设计和实现决定了中断信号的传递方式和硬件的中断处理能力。

二、GIC v3中断控制器

  ARM多核处理器里最常用的中断控制器是GIC, GIC是Generic Interrupt Controller的缩写,提供了灵活的和可扩展的中断管理方法,支持单核系统到数百个大型多芯片设计的核心。 主要作用就是接受硬件中断信号,通过一定的设置策略,然后分发给对应的CPU进行处理。
  GIC v3中断控制器是ARM公司推出的一款与cortex-A和cortex-R处理器配合使用的中断控制器,广泛应用于基于armv8的SOC设计中。GIC v3为CPU处理所有连接到其上的中断,包括管理所有的中断源、中断行为、中断分组以及中断路由方式等。同时,它还提供相应的寄存器接口用于软件对这些行为的控制。

1. GIC v3基本结构

  GIC v3包含了SPI(Shared Peripheral Interrupt)、PPI(Private Peripheral Interrupt)、SGI(Software Generated Interrupt)和LPI(Locality-Specific Peripheral Interrupt)四种中断类型,以及distributor、redistributor、ITS(Interrupt Translation Service)和CPU interface四大组件。
在这里插入图片描述
   GIC v3中,将cpu interface从GIC中抽离,放入到了cpu中,cpu interface通过AXI Stream,与gic进行通信。 当GIC要发送中断,GIC通过AXI stream接口,给cpu interface发送中断命令,cpu interface收到中断命令后,根据中断线映射配置,决定是通过IRQ还是FIQ管脚,向cpu发送中断。

1.1 Distributor

  Distributor是GIC v3中用于管理共享外设中断(SPI)的关键组件。它负责接收来自外设的SPI中断请求,并根据配置决定中断的优先级以及将中断路由到哪个Redistributor。

  • 关键特性:
    • 中断分发:Distributor根据中断的优先级、亲和性(affinity)等配置,将SPI中断路由到适当的Redistributor。
    • 优先级管理:Distributor为每个SPI中断设置优先级,确保高优先级的中断能够优先得到处理。
    • 中断状态管理:Distributor维护中断的状态信息,如中断是否激活、是否挂起等。
  • 寄存器接口:
    • GICD_系列寄存器(如GICD_ISENABLER、GICD_ICENABLER、GICD_IPRIORITYR等)用于配置Distributor的行为,包括启用/禁用中断、设置中断优先级等。

1.2 Redistributor

  Redistributor与CPU接口连接,负责将来自Distributor的中断路由到正确的CPU。在多核系统中,Redistributor确保中断被正确地分发到目标CPU或CPU组。

  • 关键特性:

    • 中断路由:Redistributor根据配置将中断路由到相应的CPU接口。
    • 亲和性管理:Redistributor支持中断的亲和性配置,允许中断被路由到特定的CPU或CPU组。
  • 寄存器接口:

    • GICR_系列寄存器(如GICR_ISENABLER、GICR_ICENABLER等)用于配置Redistributor的行为,包括启用/禁用中断、设置中断路由等。

1.3 ITS

  ITS是GIC v3中用于处理基于消息的中断(LPI)的组件。它提供LPI中断的转换服务,将来自虚拟中断源的LPI中断转换为物理中断源,并将其路由到适当的Redistributor。

  • 关键特性:
    • 中断转换:ITS将LPI中断转换为物理中断,以便在物理世界中进行处理。
    • 中断路由:ITS负责将LPI中断路由到正确的Redistributor。

1.4 CPU interface

  CPU interface是GIC v3与CPU之间的接口,负责将中断传递到它所连接到的处理器元素(PE,即CPU)。当Redistributor将中断路由到某个CPU接口时,该接口会将中断信号发送到相应的CPU。

  • 关键特性:
    • 中断传递:CPU interface将来自Redistributor的中断信号传递给CPU。
    • 中断状态管理:CPU interface可能还负责维护中断的状态信息,如中断是否已被CPU接收、是否正在处理等。

2. 中断类型与特点

  • SPI:共享外设中断,不与特定的CPU绑定,可以根据affinity配置被路由到任意CPU或一组特定的CPU上。
  • PPI:私有外设中断,每个处理器私有的中断类型,即一个特定的中断只会被路由到特定的处理器上。
  • SGI:软件生成中断,没有实际的物理连线,而是由软件通过写寄存器方式触发,只支持边沿触发。
  • LPI:基于消息的中断,LPI相关的配置保存在内存中而非寄存器。
NTID范围中断类型备注
0 - 15SGI(软件生成中断) 文本居右每个核心分别存储
16 - 31PPI(私有外设中断)每个核心分别存储
32 - 1019SPI(共享外设中断)
1020 - 1023特殊中断号用于表示特殊情况
1024 - 8191保留
8192及更大LPI(特定局部外设中断)上限由实现定义

在这里插入图片描述

  • Inactive(非活动状态):中断源当前未被触发。
  • Pending(等待状态):中断源已被触发,但尚未被处理器核心确认。
  • Active(活动状态):中断源已被触发,并且已被处理器核心确认。
  • Active and Pending(活动且等待状态):已确认一个中断实例,同时另一个中断实例正在等待处理。

每个外设中断可以是以下两种类型之一:

  • 边沿触发(Edge-triggered):
    这是一种在检测到中断信号上升沿时触发的中断,然后无论信号状态如何,都保持触发状态,直到满足本规范定义的条件来清除中断。
  • 电平触发(Level-sensitive):
    这是一种在中断信号电平处于活动状态时触发的中断,并且在电平不处于活动状态时取消触发。

3. 中断号

  在linux 内核中,我们使用IRQ number和HW interrupt ID两个ID来标识一个来自外设的中断:

  • IRQ number:CPU需要为每一个外设中断编号,我们称之IRQ Number。这个IRQ number是一个虚拟的interrupt ID,和硬件无关,仅仅是被CPU用来标识一个外设中断。
  • HW interrupt ID:对于GIC中断控制器而言,它收集了多个外设的interrupt request line并向上传递,因此,GIC中断控制器需要对外设中断进行编码。GIC中断控制器用HW interrupt ID来标识外设的中断。如果只有一个GIC中断控制器,那IRQ number和HW interrupt ID是可以一一对应的,如下图所示:
    在这里插入图片描述
      但如果是在GIC中断控制器级联的情况下,仅仅用HW interrupt ID就不能唯一标识一个外设中断,还需要知道该HW interrupt ID所属的GIC中断控制器(HW interrupt ID在不同的Interrupt controller上是会重复编码的)。

三、函数编写

3.1 相关API函数

函数名描述
irq_of_parse_and_map( )解析得到软中断号
request_irq( )注册中断
devm_request_irq( )注册中断,申请的是内核“managed”的资源
free_irq( )释放中断
*irq_handler_t( )指定一个中断处理函数
enable_irq( )中断的使能
disable_irq( )中断的屏蔽
gpio_to_irq( )将 GPIO 引脚映射到对应中断号的函数
//解析得到软中断号
unsigned int irq_of_parse_and_map(struct device_node *np, int index)
  • 参数:
    • np:节点指针
    • index:设备树节点中interrupts键对应值的下标
  • 返回值:成功返回软中断号,失败返回0
//注册中断
static inline int __must_check request_irq(unsigned int irq, irq_handler_t 
    handler,unsigned long flags, const char *name, void *dev);
  • 参数:
    • irq:软中断号(内核中用到的中断号全部都是软中断号)(设备树获取)
    • handler:中断处理函数指针
    • flags:中断触发方式
      • IRQF_TRIGGER_RISING //上升沿
      • IRQF_TRIGGER_FALLING //下降沿
      • IRQF_TRIGGER_HIGH //高电平
      • IRQF_TRIGGER_LOW //低电平
      • IRQF_SHARED //共享中断
    • name:中断的名字
      cat /proc/interrupts 命令查看(设备号的查看方式 cat /proc/device)
    • dev:给中断处理函数传递的参数
  • 返回值:成功返回0,失败返回错误码

  此函数与request_irq()的区别是devm_开头的API申请的是内核“managed”的资源,一般不需要在出错处理和 remove()接口里再显式的释放。

int devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t 
	handler,unsigned long irqflags, const char *devname, void *dev_id);
  • 参数:
    • dev:指向您的设备的 struct device 结构体指针。这个结构体包含了设备的各种信息,并且允许设备管理器跟踪与该设备相关的所有资源。
    • irq:要请求的中断号。
    • handler:当中断触发时要调用的处理函数。
    • irqflags:标志位,用于指定中断处理函数的行为,如 IRQF_SHARED 允许多个处理程序共享同一个中断。
    • devname:与中断关联的名称,通常用于调试和日志记录。
    • dev_id:传递给中断处理函数的参数,允许您在中断处理程序中区分不同的中断源或设备实例。
  • 返回值:
    • 如果成功请求了中断,则返回 0。
    • 如果失败(例如,由于中断号无效、中断已被占用且未标记为可共享等),则返回负的错误码。

注:这里简单介绍一下中断处理函数指针

//typedef irqreturn_t (*irq_handler_t)(int, void *);
irqreturn_t key_irq_handle(int irqno,void *dev)
{
   //中断的处理---中断处理函数中不能加延时耗时的操作
    return IRQ_NONE;    //失败
    return IRQ_HANDLED; //成功
}
//释放中断
const void *free_irq(unsigned int irq, void *dev_id);
  • 参数:
    • irq:软中断号
    • dev_id:给中断处理函数传递的参数
  • 返回值:返回设备的名字
//在中断申请时需要指定一个中断处理函数
irqreturn_t (*irq_handler_t)(int irq, void * dev);
  • 参数:
    • int irq:表示触发中断的中断号(IRQ number)
    • void *dev:一个指向任何类型数据的指针,通常由 request_irq 或 devm_request_irq 函数的调用者提供,并传递给中断处理函数。这个指针通常用于传递与中断相关的设备或驱动程序的上下文信息
  • 返回值:
    • irqreturn_t类型:枚举类型变量
      • IRQ_NONE(0 << 0): 中断没有被处理
      • IRQ_HANDLED (1 << 0):中断被成功处理
      • IRQ_WAKE_THREAD(1 << 1):在中断服务函数是使用“上半部分”和“下半部分”实现
//中断的屏蔽和使能
void enable_irq(unsigned int irq);
void disable_irq(unsigned int irq);
  • 参数:
    • irq:指定的“内核中断号”
  • 返回值:无
//将 GPIO 引脚映射到对应中断号的函数,它的作用是根据给定的 GPIO 引脚号,获取与之关联的中断号。
#include <linux/gpio.h>
unsigned int gpio_to_irq(unsigned int gpio);
  • 参数:
    • gpio:要映射的 GPIO 引脚号。
  • 返回值:
    • 成功:返回值为该 GPIO 引脚所对应的中断号。
    • 失败:返回值为负数,表示映射失败或无效的 GPIO 引脚号。

3.2 驱动初始化函数

static int __init button_driver_init(void)
{
	int error = -1;

	//采用动态分配的方式,获取设备编号,次设备号为0,
	error = alloc_chrdev_region(&button_devno, 0, DEV_CNT, DEV_NAME);
	if (error < 0)
	{
		printk("fail to alloc button_devno\n");
		goto alloc_err;
	}

	//关联字符设备结构体cdev与文件操作结构体file_operations
	button_chr_dev.owner = THIS_MODULE;
	cdev_init(&button_chr_dev, &button_chr_dev_fops);

	//添加设备至cdev_map散列表中
	error = cdev_add(&button_chr_dev, button_devno, DEV_CNT);
	if (error < 0) 
	{
		printk("fail to add cdev\n");
		goto add_err;
	}

	class_button = class_create(THIS_MODULE, DEV_NAME); //创建类
	//创建设备 DEV_NAME 指定设备名
	device_button = device_create(class_button, NULL, button_devno, NULL, DEV_NAME);

	return 0;

add_err:
	// 添加设备失败时,需要注销设备号
	unregister_chrdev_region(button_devno, DEV_CNT);    
	printk("\n error! \n");
	
alloc_err:
	return -1;
}

3.3 operations函数

3.3.1 open函数

static int button_open(struct inode *inode, struct file *filp)
{
    int res = -1;

    //获取按键 设备树节点
    button_device_node = of_find_node_by_path("/button_interrupt");
    if(NULL == button_device_node)
    {
            printk("of_find_node_by_path error!");
            return -1;
    }

    //获取按键使用的GPIO
    button_GPIO_number = of_get_named_gpio(button_device_node ,"button-gpios", 0);
    if(0 == button_GPIO_number)
    {
            printk("of_get_named_gpio error");
            return -1;
    }

    //申请GPIO,记得释放
    res = gpio_request(button_GPIO_number, "button_gpio");
    if(error < 0)
    {
            printk("gpio_request error");
            gpio_free(button_GPIO_number);
            return -1;
    }
    
	//设置为输入模式
    res = gpio_direction_input(button_GPIO_number);

    //获取中断号
    interrupt_number = irq_of_parse_and_map(button_device_node, 0);
    printk("\n interrupt_number =  %d \n",interrupt_number);

    //申请中断, 记得释放
    res = request_irq(interrupt_number,button_irq_hander,IRQF_TRIGGER_RISING,"button_interrupt",NULL);
    if(error != 0)
    {
            printk("request_irq error");
            free_irq(interrupt_number, NULL);
            return -1;
    }
    return 0;
}

3.3.2 .read

static int button_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    int error = -1;
    int button_countervc = 0;

    //读取按键状态值
    button_countervc = atomic_read(&button_status);

    //结果拷贝到用户空间
    error = copy_to_user(buf, &button_countervc, sizeof(button_countervc));
    if(error < 0)
    {
            printk_red("copy_to_user error");
            return -1;
    }
    //清零按键状态值
    atomic_set(&button_status,0);
    return 0;
}

3.3.3 .release

static int button_release(struct inode *inode, struct file *filp)
{
	
    //释放申请的引脚,和中断
    gpio_free(button_GPIO_number);
    free_irq(interrupt_number, device_button);
    printk("release over!");
    return 0;
}

3.4 中断函数

//定义整型原子变量,保存按键状态 ,设置初始值为0
atomic_t   button_status = ATOMIC_INIT(0);  

static irqreturn_t button_irq_hander(int irq, void *dev_id)
{
	printk("hander has entered!");
    //按键状态加一
    atomic_inc(&button_status);
    return IRQ_HANDLED;
}

四、设备树的编辑

1. 设备树插件格式

  设备树插件(Device Tree Overlay)是一种用于设备树(Device Tree)的扩展机制,它在Linux内核的嵌入式系统中发挥着重要作用。设备树插件允许在运行时动态修改设备树的内容,以便添加、修改或删除设备节点和属性。它提供了一种灵活的方式来配置和管理硬件设备,而无需重新编译整个设备树。通过使用设备树插件,开发人员可以在不重新启动系统的情况下对硬件进行配置更改。

#用于指定dts的版本
 /dts-v1/;
 
#表示允许使用未定义的引用并记录它们,设备树插件中可以引用主设备树中的节点
#这些“引用的节点”对于设备树插件来说就是未定义的,所以设备树插件应该加上“/plugin/”
/plugin/;

&{/} {
    /*此处在根节点"/"下,添加要插入的节点或者属性*/
};

&XXXXX {
    /*此处在节点"XXXXX"下,添加要插入的节点或者属性*/
};
    .......

2. 设备树插件的编写

#触发方式
#define IRQ_TYPE_NONE           0
#define IRQ_TYPE_EDGE_RISING    1
#define IRQ_TYPE_EDGE_FALLING   2
#define IRQ_TYPE_EDGE_BOTH      (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH     4
#define IRQ_TYPE_LEVEL_LOW      8

&{/} {
        #新增的button_interrupt节点
        button_interrupt: button_interrupt {
            status = "okay";
            compatible = "button_interrupt";
            #配置按键引脚
            button-gpios = <&gpio0 RK_PB0 GPIO_ACTIVE_LOW>;
            #插件按键引脚的复用信息
            pinctrl-names = "default";
            pinctrl-0 = <&button_interrupt_pin>;
            #表示父中断控制节点是gpio0
            interrupt-parent = <&gpio0>;
            #表示中断引脚,触发方式
            interrupts = <RK_PB0 IRQ_TYPE_LEVEL_LOW>;
        };
    };

&{/pinctrl} {
    pinctrl_button {
        button_interrupt_pin: button_interrupt_pin {
            rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
        };
    };
};

免责声明:本文参考了野火的部分资料,仅供学习参考使用,若有侵权或勘误请联系笔者。

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

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

相关文章

【自动驾驶】针对低速无人车的线控底盘技术

目录 术语定义 一般要求 操纵装置 防护等级 识别代号 技术要求 通过性要求 直线行驶稳定性 环境适应性要求 功能安全要求 信息安全要求 故障处理要求 通信接口 在线升级(OTA) 线控驱动 动力性能 驱动控制响应能力 线控制动 行车制动 制动响应能力 线控转向 总体要求 线控…

计算机网络 期末复习(谢希仁版本)第5章

**屏蔽作用&#xff1a;**运输层向高层用户屏蔽了下面网络核心的细节&#xff08;如网络拓扑、所采用的路由选择协议等&#xff09;&#xff0c;使应用进程看见的就是好像在两个运输层实体之间有一条端到端的逻辑通信信道。 10. 端口用一个 16 位端口号进行标志&#xff0c;允许…

力扣 496. 下一个更大元素 I

题目来源&#xff1a;https://leetcode.cn/problems/next-greater-element-i/description/ C题解1&#xff1a;暴力解决 class Solution { public:vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {int len1 nums1.size(…

C# WPF入门学习主线篇(六)—— TextBox常见属性和事件

欢迎回到C# WPF入门学习系列的第六篇。在前面的文章中&#xff0c;我们探讨了按钮&#xff08;Button&#xff09;的事件处理。今天&#xff0c;我们将继续学习另一个常用的WPF控件——TextBox。本文将介绍 TextBox 的常见属性和事件&#xff0c;并通过示例代码展示如何在实际应…

【Python数据类型的奥秘】:构建程序基石,驾驭信息之海

文章目录 &#x1f680;Python数据类型&#x1f308;1. 基本概念⭐2. 转化&#x1f44a;3. 数值运算&#x1f4a5;4. 数值运算扩展(math库常用函数) &#x1f680;Python数据类型 &#x1f308;1. 基本概念 整数&#xff08;int&#xff09;&#xff1a;整数是没有小数部分的数…

GRS认证是什么?GRS认证的要求是什么?

GRS认证&#xff08;Global Recycled Standard&#xff09;是全球回收标准认证&#xff0c;它是一个自愿性的、针对产品回收成分和供应链可追溯性的国际标准。GRS认证的目标是为纺织业的公司提供一个具有透明度和信任度的工具&#xff0c;以证明其产品的回收材料含量&#xff0…

C语言数据结构快速排序的非递归、归并排序、归并排序的非递归等的介绍

文章目录 前言一、快速排序非递归二、归并排序五、归并排序非递归总结 前言 C语言数据结构快速排序的非递归、归并排序、归并排序的非递归等的介绍 一、快速排序非递归 快速排序非递归的定义 快速排序非递归&#xff0c;需要使用栈来实现。将左右下标分别push到栈中。在栈为…

Redis-SDS 的定义

1.简介 Redis中的SDS&#xff08;Simple Dynamic String&#xff0c;简单动态字符串&#xff09;是一种专为Redis设计的字符串表示方式&#xff0c;旨在改进C语言中原生字符串的局限性。 2.SDS的核心结构 SDS结构不仅存储字符串的实际内容&#xff0c;还包括了额外的信息来优…

达梦数据库的配置与安装

1. 下载压缩包&#xff0c;点击链接产品下载 | 达梦数据库 (dameng.com) 本人只是测试需要&#xff0c;所以选择的是开发版&#xff08;X86平台&#xff09; 2. 解压压缩包 3.点击iso的应用 4.选择挂载 这个是因为我有装挂载软件&#xff0c;如果没有装&#xff0c;麻烦搜索下…

基于Raspi的Opencv-Python开发笔记

本文所有未强调 “windows终端” 的 “终端”字眼&#xff0c;都是默认树莓派的终端 系统版本 系统版本有必要强调一下&#xff0c;因为不同版本很多操作需要修改 在终端输入uname -a Release就是版本号&#xff0c;Codename是版本名 以下操作仅在此版本验证可行 使能摄像…

解决找不到api-ms-win-crt-runtime-l1-1-0.dll问题的5种方法

电脑已经成为我们生活和工作中不可或缺的工具&#xff0c;然而&#xff0c;由于各种原因&#xff0c;我们可能会遇到一些常见的问题&#xff0c;其中之一就是电脑缺失api-ms-win-crt-runtime-l1-1-0.dll文件。这个问题可能会导致电脑出现错误提示、程序无法正常运行等困扰。为了…

Zookeeper复习

一、入门 1、概念 zookeeper文件系统通知机制 2.特点 1&#xff09;、一个领导者&#xff0c;多个跟随者组成的集群。 2&#xff09;、集群中只要有半数以上存活机制&#xff0c;zookeeper集群能正产服务。zk适合安装奇数台。 3&#xff09;、全局数据一致&#xff1a;每…

一次 K8s 故障诊断:从 CPU 高负载到存储挂载泄露根源揭示

一、背景 现代软件部署中&#xff0c;容器技术已成为不可或缺的一环&#xff0c;在云计算和微服务架构中发挥着核心作用。随着容器化应用的普及&#xff0c;确保容器环境的可靠性成为了一个至关重要的任务。这就是容器SRE&#xff08;Site Reliability Engineering&#xff0c…

【强烈推荐】四元数与三维旋转

目录 1 强烈推荐讲解四元数与三维旋转的这篇文章&#xff0c;深入浅出2 笔记2.1 复数2.1.1 复数的定义2.1.2 复数的乘法与二维旋转 2.2 三维空间中的旋转2.2.1 角轴2.2.2 旋转的分解 2.3 四元数2.3.1 四元数的定义2.3.2 四元数的乘法2.3.3 四元数与三维旋转2.3.4 三维旋转的矩阵…

【Excel】Excel中将日期格式转换为文本格式,并按日期显示。

【问题需求】 在使用excel进行数据导入的过程中&#xff0c; 有的软件要求日期列必须是文本格式。 但是直接将日期列的格式改为文本后&#xff0c;显示一串数字&#xff0c;而不按日期显示。 进而无法导入使用。 【解决方法】 使用【TXET】函数公式进行处理&#xff0c; 在单…

转转回收业务策略中心的实践

1 背景 回收业务发展日益壮大&#xff0c;我们在邮寄、上门、门店三大履约模式下的业务逻辑日益复杂。同样都是在做回收这一个业务&#xff0c;即便履约方式不同&#xff0c;也有很多业务概念是一致的。为了避免各个业务闷头造轮子&#xff0c;同时又能拉齐三端的业务标准&…

数据库(19)——字符串函数

函数是指一段可以直接被另一段程序调用的程序代码。 常用的函数 函数功能CONCAT(S1,S2...Sn)字符串拼接LOWER(str)将字符串全部转换为小写UPPER(str)将字符串全部转换为大写LPAD(str,n,pad) 用字符串pad对str的左边进行填充RPAD(str,n,pad)用字符串…

这款国内版Bookstack平替也很好用

对于企业、团队或个人来说&#xff0c;一个高效、易用的知识库系统就是提升工作效率和团队协作的利器。一款国内版的BookStack平替——HelpLook AI知识库&#xff0c;它不仅功能强大&#xff0c;而且操作简单&#xff0c;对于国内使用者来说刚刚好&#xff0c;跟着LookLook同学…

DP读书:《ModelArts人工智能应用开发指南》(一)人工智能技术、应用平台

怎么用ModelArts人工智能应用 训练底座训练案例 盘古矿山模型Main config.py 训练底座 训练案例 盘古矿山模型 Main 下面是快速助手 https://support.huaweicloud.com/qs-modelarts/modelarts_06_0006.html 准备开发环境 在ModelArts控制台的“ 开发环境 > Notebook”页面…

项目部署服务器--浏览器拒绝访问问题

一、检查自己的环境 是本地环境、还是虚拟环境 当您使用 Gunicorn 启动 Flask 应用并监听 0.0.0.0:5000 时&#xff0c;您的 Flask 应用已经可以在服务器上运行并通过该端口提供服务了。但是&#xff0c;0.0.0.0 是一个特殊的 IP 地址&#xff0c;它表示“所有可用的网络接口”…