Linux INPUT 子系统实验

news2025/1/18 3:26:00

目录

一、input 子系统简介

input_dev 结构体

二、驱动编写

 1、宏定义

 2、按键结构体和按键中断结构体

 3、中断处理函数

4、定时器处理函数

 5、注册input_dev

 6、驱动出口

代码

 验证

打印现象解析

1、input_event 结构体

2、打印解释

三、APP编写

app代码如下

验证


        按键、鼠标、键盘、触摸屏等都属于输入(input)设备, Linux 内核为此专门做了一个叫做 input子系统的框架来处理输入事件。输入设备本质上还是字符设备,只是在此基础上套上了 input 框架,用户只需要负责上报输入事件,比如按键值、坐标等信息, input 核心层负责处理这些事件

一、input 子系统简介

        input 就是输入的意思,因此 input 子系统就是管理输入的子系统,和 pinctrl、 gpio 子系统
一样,都是 Linux 内核针对某一类设备而创建的框架。比如按键输入、键盘、鼠标、触摸屏等等这些都属于输入设备,不同的输入设备所代表的含义不同,按键和键盘就是代表按键信息,鼠标和触摸屏代表坐标信息,因此在应用层的处理就不同,对于驱动编写者而言不需要去关心应用层的事情,我们只需要按照要求上报这些输入事件即可。为此 input 子系统分为 input 驱动层、 input 核心层、 input 事件处理层,最终给用户空间提供可访问的设备节点

input 子系统结构图

 中左边就是最底层的具体设备,比如按键、 USB 键盘/鼠标等,

中间部分属于Linux 内核空间,分为驱动层、核心层和事件层,

最右边的就是用户空间,所有的输入设备以文件的形式供用户应用程序使用

可以看出 input 子系统用到了我们前面讲解的驱动分层模型,我们编写驱动程序的时候只需要关注中间的驱动层、核心层和事件层,这三个层的分工如下:

驱动层:输入设备的具体驱动程序,比如按键驱动程序,向内核层报告输入内容。
核心层:承上启下,为驱动层提供输入设备注册和操作接口。通知事件层对输入事件进行处理。
事件层:主要和用户空间进行交互。

input_dev 结构体

表示 input设备,此结构体定义在 include/linux/input.h 文件中

 struct input_dev {
2 const char *name;
3 const char *phys;
4 const char *uniq;
5 struct input_id id;
6
7 unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
8
9 unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; /* 事件类型的位图 */
10 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; /* 按键值的位图 */
11 unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; /* 相对坐标的位图 */
12 unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; /* 绝对坐标的位图 */
13 unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; /* 杂项事件的位图 */
14 unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; /*LED 相关的位图 */
15 unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];/* sound 有关的位图 */
16 unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; /* 压力反馈的位图 */
17 unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; /*开关状态的位图 */
......
18 bool devres_managed;
};

9行, evbit 表示输入事件类型,可选的事件类型定义在 include/uapi/linux/input.h 文件中,事件类型如下:

#define EV_SYN 0x00 /* 同步事件 */
#define EV_KEY 0x01 /* 按键事件 */
#define EV_REL 0x02 /* 相对坐标事件 */
#define EV_ABS 0x03 /* 绝对坐标事件 */
#define EV_MSC 0x04 /* 杂项(其他)事件 */
#define EV_SW 0x05 /* 开关事件 */
#define EV_LED 0x11 /* LED */
#define EV_SND 0x12 /* sound(声音) */
#define EV_REP 0x14 /* 重复事件 */
#define EV_FF 0x15 /* 压力事件 */
#define EV_PWR 0x16 /* 电源事件 */
#define EV_FF_STATUS 0x17 /* 压力状态事件 */

要使用到按键,那么就需要注册 EV_KEY 事件,如果要使用连按功能还需要注册 EV_REP 事件。
10行,本章要使用按键事件,因此要用到 keybit, keybit 就是按键事件使用的位图, Linux 内核定义了很多按键值,这些按键值定义在 include/uapi/linux/input.h 文件中,按键值如下

 #define KEY_RESERVED 0
 #define KEY_ESC 1
 #define KEY_1 2
 #define KEY_2 3
 #define KEY_3 4
 #define KEY_4 5
 #define KEY_5 6
 #define KEY_6 7
 #define KEY_7 8
 #define KEY_8 9
 #define KEY_9 10
 #define KEY_0 11
....

任意一个,这里开发板上的 KEY 按键值设置为 KEY_0

二、驱动编写

本章实验在“中断实验”的基础上修改,修改makefiel,添加头文件#include <linux/input.h>

 1、宏定义

 2、按键结构体和按键中断结构体

在设备key结构体里面定义inputdev 

 3、中断处理函数

 和中断实验的一样,不变

4、定时器处理函数

 62-69行,当下按键或者释放的时候,都要上报,input 设备都是具有输入功能的,但是具体是什么样的输入值 Linux 内核是不知道的,我们需要获取到具体的输入值,或者说是输入事件,然后将输入事件上报给 Linux 内核。这里设置EV_KEY按键事件,按键值选了KEY_0

input_event 函数,此函数用于上报指定的事件以及对应的值,函数原型如下

void input_event(struct input_dev *dev,
                                unsigned int type,
                                unsigned int code,
                                int value)

dev:需要上报的 input_dev

type: 上报的事件类型,比如 EV_KEY。
code: 事件码,也就是我们注册的按键值,比如 KEY_0、 KEY_1 等等。
value:事件值,比如 1 表示按键按下, 0 表示按键松开。
返回值: 无

当我们上报事件以后还需要使用 input_sync 函数来告诉 Linux 内核 input 子系统上报结束,
input_sync 函数本质是上报一个同步事件,此函数原型如下所示:

void input_sync(struct input_dev *dev)
dev:需要上报同步事件的 input_dev。返回值: 无

 5、注册input_dev

 140行,编写 input 设备驱动的时候我们需要先申请一个 input_dev 结构体变量,使用
input_allocate_device 函数来申请一个 input_dev,此函数原型如下所示:

struct input_dev *input_allocate_device(void)
参数:无。返回值: 申请到的 input_dev。

 146行,设置 input_dev 名字

152行,设置产生按键事件、重复事件和设置产生哪些按键值.

154行,申请好一个 input_dev 以后就需要初始化这个 input_dev,需要初始化的内容主要为事件类型(evbit)和事件值(keybit)这两种。 input_dev 初始化完成以后就需要向 Linux 内核注册input_dev了,需要用到 input_register_device 函数,此函数原型如下:

int input_register_device(struct input_dev *dev)
dev:要注册的 input_dev 。
返回值: 0, input_dev 注册成功;负值, input_dev 注册失败。

 6、驱动出口

 177-178行,注销 input 驱动的时候也需要使用 input_unregister_device 函数来注销掉前面注册
的 input_dev, input_unregister_device 函数原型如下:

void input_unregister_device(struct input_dev *dev)
dev:要注销的 input_dev 。返回值: 无。

注销的 input 设备的话需要使用 input_free_device 函数来释放掉前面申请到的input_dev, input_free_device 函数原型如下:

void input_free_device(struct input_dev *dev)
dev:需要释放的 input_dev。返回值: 无。 

代码

#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_irq.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/atomic.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/input.h>

#define KEYINPUT_CNT 1
#define KEYINPUT_NAME "keyinput"
#define KEY_NUM 1       /* 按键数量 	*/
#define KEY0VALUE 0X01  /* KEY0按键值 	*/
#define INVAKEY 0XFF    /* 无效的按键值 */

/*key结构体*/
struct irq_keydesc{
    int gpio;  /*io编号*/
    int irqnum; /*中断号*/
    unsigned char value; /*键值*/
    char name[10]; /*名字*/

    irqreturn_t(*handler) (int ,void *); /*中断处理函数*/
};
/*keyinput结构体*/
struct keyinput_dev{
    struct device_node *nd;
    struct irq_keydesc irqkey[KEY_NUM];
    struct timer_list timer;
    
    struct input_dev *inputdev;/*输入设备*/
};
struct keyinput_dev keyinputdev;

/*按键中断处理函数*/
static irqreturn_t key0_handler(int irq,void *dev_id){
    
    struct keyinput_dev * dev = dev_id;
    dev->timer.data = (volatile unsigned long)dev_id;
    mod_timer(&dev->timer,jiffies + msecs_to_jiffies(20));/*20ms*/

    return IRQ_HANDLED;
}
/*定时器处理函数*/
static void timer_func(unsigned long arg){
    int value = 0;
    struct keyinput_dev *dev = (struct keyinput_dev *)arg;
    value = gpio_get_value(dev->irqkey[0].gpio);
    if(value == 0){/*按下*/
        /*上报按键值*/
        input_event(dev->inputdev,EV_KEY,KEY_0,1);
        input_sync(dev->inputdev);
    }else if(value == 1){/*释放*/
        /*上报按键值*/
        input_event(dev->inputdev,EV_KEY,KEY_0,0);
        input_sync(dev->inputdev);
    }

}
/*按鍵初始化*/
static int keyio_init(struct keyinput_dev *dev){
    int i,ret =0 ;
    /*按鍵初始化*/
    dev->nd = of_find_node_by_path("/key");
    if(dev->nd == NULL){
        ret = -EINVAL;
        goto fail_nd;
    }
    for(i=0;i<KEY_NUM;i++){
        dev->irqkey[i].gpio = of_get_named_gpio(dev->nd,"key-gpios",i);
        if(dev->irqkey[i].gpio < 0){
            ret = -EINVAL;
            goto fail_gpio;
        }
    }
    for(i=0;i<KEY_NUM;i++){
        memset(dev->irqkey[i].name,0,sizeof(dev->irqkey[i].name));
        sprintf(dev->irqkey[i].name,"KEY%d",i);
        ret = gpio_request(dev->irqkey[i].gpio , dev->irqkey[i].name);
        if(ret){
            ret = -EBUSY;
            printk("IO %d can't request\r\n",dev->irqkey[i].gpio);
            goto fail_request;
        }
        gpio_direction_input(dev->irqkey[i].gpio);
        /*获取中断号*/
        dev->irqkey[i].irqnum = gpio_to_irq(dev->irqkey[i].gpio);
#if 0
        dev->irqkey[i].irqnum = irq_of_parse_and_map(dev->nd,i);
 #endif
    }
    dev->irqkey[0].handler = key0_handler;
    dev->irqkey[0].value   = KEY_0;
        /*按键中断初始化*/
    for(i=0;i<KEY_NUM;i++){
        ret = request_irq(dev->irqkey[i].irqnum,dev->irqkey[i].handler,
                            IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING,
                            dev->irqkey[i].name,&keyinputdev);
        if(ret){
            printk("irq %d request failed!\r\n",dev->irqkey[i].irqnum);
            goto fail_irq;
        }
    }
    /*初始化定时器*/
    init_timer(&keyinputdev.timer);
    keyinputdev.timer.function = timer_func;

    return 0;
fail_irq:
    for(i=0;i<KEY_NUM;i++){
        gpio_free(dev->irqkey[i].gpio);
    }
fail_request:
fail_gpio:
fail_nd:
    return ret;
}

static int __init keyinput_init(void){
    int ret = 0;
    /*初始化IO*/
    ret = keyio_init(&keyinputdev);
    if(ret < 0){
        goto fail_keyinit;
    }
    /*注册input_dev*/
    keyinputdev.inputdev = input_allocate_device();
    if(keyinputdev.inputdev == NULL)
    {
        ret = -EINVAL;
        goto fail_keyinit;
    }
    keyinputdev.inputdev->name = KEYINPUT_NAME;
    /*按键事件*/
    __set_bit(EV_KEY , keyinputdev.inputdev->evbit);
    /*重复事件*/
    __set_bit(EV_REP , keyinputdev.inputdev->evbit);
    /*按键值*/
    __set_bit(KEY_0 , keyinputdev.inputdev->keybit);

    ret = input_register_device(keyinputdev.inputdev);
    if(ret){
        goto fail_input_register;
    }
    return 0;
fail_input_register:
    input_free_device(keyinputdev.inputdev);
fail_keyinit:
    return ret;
}
static void __exit keyinput_exit(void){
    int i=0;
    /*释放中断*/
    for(i=0;i<KEY_NUM;i++){
        free_irq(keyinputdev.irqkey[i].irqnum,&keyinputdev);
    }
    /*释放IO*/
    for(i=0;i<KEY_NUM;i++){
        gpio_free(keyinputdev.irqkey[i].gpio);
    }
    /*删除定时器*/
    del_timer_sync(&keyinputdev.timer);
    /*注销inpu_dev*/
    input_unregister_device(keyinputdev.inputdev);
    input_free_device(keyinputdev.inputdev);

    printk("keyinputdev_exit\r\n");
}

module_init(keyinput_init);
module_exit(keyinput_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ba che kai qi lai");

 验证

先查看一下开发板input目录 

 这里自带event0和mice

加载驱动和卸载驱动

 每一次加载,input会自增

加载驱动之后,再次查看input目录

多了一个event1

利用hexdump,接收 显示=原始的按键数据

输入命令之后,按下按键就会打印出数据,一直按着不放一直打印

打印现象解析

        先了解input_event 结构体

1、input_event 结构体

        Linux 内核使用 input_event 这个结构体来表示所有的输入事件, input_envent 结构体定义在
include/uapi/linux/input.h 文件中,结构体内容如下:

struct input_event {
         struct timeval time;
        __u16 type;

        __u16 code;
        __s32 value;
 };

time:时间,也就是此事件发生的时间,为 timeval 结构体类型, timeval 结构体定义如下:

 typedef long __kernel_long_t;

 typedef __kernel_long_t __kernel_time_t;
 typedef __kernel_long_t __kernel_suseconds_t;


struct timeval {
 __kernel_time_t tv_sec; /* 秒 */
 __kernel_suseconds_t tv_usec; /* 微秒 */
 };

可以看出, tv_sec 和 tv_usec 这两个成员变量都为 long 类型,也就是 32位

type: 事件类型,比如 EV_KEY,表示此次事件为按键事件,此成员变量为 16 位。
code: 事件码,比如在 EV_KEY 事件中 code 就表示具体的按键码,如: KEY_0、 KEY_1等等这些按键。此成员变量为 16 位。
value: 值,比如 EV_KEY 事件中 value 就是按键值,表示按键有没有被按下,如果为 1 的话说明按键按下,如果为 0 的话说明按键没有被按下或者按键松开了

        input_envent 这个结构体非常重要,因为所有的输入设备最终都是按照 input_event 结构体
呈现给用户的,用户应用程序可以通过 input_event 来获取到具体的输入事件或相关的值,比如
按键值等

2、打印解释

抽出部分打印结果,如下图

基本都是对应上面介绍的input_event结构体,type 为事件类型, EV_KEY 按键事件值为 1, EV_SYN 同步事件值为0。因此第 1 行表示 EV_KEY 事件,第 2 行表示 EV_SYN 事件

code 为事件编码,也就是按键号,KEY_0 这个按键编号为 11,对应的十六进制为 0xb,因此第
1 行表示 KEY_0 这个按键事件

value 就是按键值,为 1 表示按下,为 0 的话表示松开

第 1 行,按键(KEY_0)按下事件。
第 2 行, EV_SYN 同步事件,因为每次上报按键事件以后都要同步的上报一个 EV_SYN 事件。
第 3 行,按键(KEY_0)松开事件。
第 4 行, EV_SYN 同步事件,和第 2 行一样,后面的都一样

下面编写APP测试

三、APP编写

主要就是定义一个input_event结构体

 *input_event结构图变量*/
static struct input_event inputevent;

45行,判断是属于key还是属于btn事件,查看宏定义

 可以看到,超过BTN_MISC的就是btn事件,一般key用来表示键盘的,一般都用btn作为按键,这次就不修改了,以后使用btn做按键即可

app代码如下

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/input.h>

/*
    argc:应用程序参数个数(argv数组元素个数)
    argv:具体参数,也可以写作char **argv
    ./keyinputAPP <filename>    
    ./keyinputAPP  /dev/input/ecent1
*/

/*input_event结构图变量*/
static struct input_event inputevent;

int main(int argc, char *argv[])
{
    int fd,err;
    char *filename;
    
    /*判断命令行输入参数是否正确*/
    if(argc != 2){
        printf("error usage!\r\n");
        return -1;
    }
    /*用指针指向文件*/
    filename = argv[1];
    /*打开文件*/
    fd = open(filename , O_RDWR);
    if(fd < 0){
        printf("file open failed\r\n",filename);
        return -1;
    }
   
    while(1){
        err = read(fd,&inputevent,sizeof(inputevent));
        if(err>0){/*数据读取成功*/
            switch(inputevent.type){
                case EV_KEY:
                    if(inputevent.code < BTN_MISC){
                         printf("EV_KEY事件,key %d %s\r\n", inputevent.code,
                                        inputevent.value?"press":"release");
                    }else{
                        printf("button %d %s\r\n", inputevent.code,
                                        inputevent.value?"press":"release");
                    }     
                    break;
                case EV_SYN:
                    printf("EV_SYN事件\r\n");
                    break;
                case EV_ABS:
                    printf("EV_ABS事件");
                    break;
            }
        }else{
            printf("读取数据失败\r\n");
        }
    }

    /*关闭文件*/
    close(fd);

    return 0;
}

验证

加载驱动之后,按下按键就会打印对应事件,并且打印按键号以及同步事件 

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

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

相关文章

【操作方法】windows开启、关闭防火墙方法

【操作方法】windows开启、关闭防火墙方法一、命令法1.启动或关闭Windows Default 防火墙2.选择启动或关闭二、鼠标点击法1.首先将查看类型选择为“类别”2.系统和安全3.Windows Defender 防火墙4.启动或关闭Windows Default 防火墙5.选择启动或关闭一、命令法 点击按键WinR打…

基于OBD系统的量产车评估测试(PVE)

在轻型汽车污染物排放限值及测量方法&#xff08;中国第六阶段&#xff09;中&#xff0c;除了对汽车尾气排放等制定了更为严格的限制之外&#xff0c;也在OBD系统认证项目中增加了新的要求——量产车评估&#xff08;Production Vehicle Evaluation&#xff09;测试。该测试由…

在码匠中使用 Microsoft SQL Server

目录 在码匠中集成 Microsoft SQL Server 在码匠中使用 Microsoft SQL Server 关于码匠 SQL Server 是 Microsoft 公司推出的关系型数据库管理系统。具有使用方便、可伸缩性好、与相关软件集成程度高等优点。Microsoft SQL Server 是一个功能全面的数据库平台&#xff0c;使…

Lecture1 Welcome Stanford CS229 Machine Learning|2018 Autumn|吴恩达机器学习

1:15:20目录机器学习类比跳棋游戏&#xff0c;理解机器学习的概念&#xff1a;很多人坐在电脑旁玩游戏或跳棋好几天&#xff0c;这就是经验E&#xff1b;任务T是指下跳棋的任务&#xff1b;性能度量P可能是指在与下一个对手下棋时/在下一场跳棋中获胜的机会是多少&#xff1f;监…

安装TDengine 服务端和客户端——客户端连不上问题解决

客户端连不上问题解决1. 下载安装服务端2. 下载安装客户端2.1 修改hosts文件2.2 修改客户端taos.cfg 文件安装中出现的问题问题解决1. 下载安装服务端 根据服务端系统不同 下载不同的安装包 &#xff0c;按照参考网址&#xff1a;https://docs.tdengine.com/get-started/packa…

接口电子器件中的光耦合器模块

工业电子设备在电气噪声和机械挑战性的环境中运行。问题在于&#xff0c;自动化、控制和仪表组件依赖于没有电气干扰或失真的精确信号来正常运行。因此&#xff0c;光耦合器模块通常被工程师用作信号源以及电源、工业控制和其他组件之间的信号保护中介。 在工业应用中&#xf…

基于自定义训练函数的BP神经网络回归分析

目录 背影 BP神经网络的原理 BP神经网络的定义 BP神经网络的神经元 BP神经网络的激活函数 BP神经网络的传递函数 基于自定义训练函数的BP神经网络回归分析 背影 BP神经网络是一种成熟的神经网络&#xff0c;拥有很多训练函数&#xff0c;传递函数&#xff0c;激活函数&#x…

创建自助服务知识库的指南

在SaaS领域&#xff0c;自助文档是你可以在客户登录你的网站时为他们提供的最灵活的帮助方式&#xff0c;简单来说&#xff0c;一个自助知识库是一个可以帮助许多客户的文档&#xff0c;拥有出色的自助服务知识库&#xff0c;放在官网或者醒目的地方&#xff0c;借助自助服务知…

vue H5跳转小程序报错:config:fail,Error: 系统错误,错误码:63002,invalid signature

微信开发者工具下载地址与更新日志 错误码&#xff1a;63002,invalid signature 无效的签名 附录5 微信网页开发 /JS-SDK说明文档 微信 JS 接口签名校验工具 全局返回码说明 ​ 排查步骤 确认签名算法正确&#xff0c;可用 http://mp.weixin.qq.com/debug/cgi-bin/sand…

【Python学习笔记】第二十二节 Python XML 解析

一、什么是XMLXML即ExtentsibleMarkup Language(可扩展标记语言)&#xff0c;是用来定义其它语言的一种元语言。XML 被设计用来传输和存储数据。XML 是一套定义语义标记的规则&#xff0c;它没有标签集(tagset)&#xff0c;也没有语法规则(grammatical rule)。任何XML文档对任何…

2023年金三银四必备软件测试常见面试题1500问!!!【Linux篇】

六、Linux6.1 Linux系统你是怎么用的?[在测试1、执行的过程中&#xff0c;我们发现的bug&#xff0c;有时候需要定位bug&#xff0c;协助开发修复bug时需要在linux里通过命令tail-200或tail-500查看当天的日志的后面多少行或者前面多少行定位bug或者通过tail -f来查看日志里的…

线程池阻塞问题

问题 记录一下生产环境出现的问题。。。 几天生产环境有同事反映分页查询一直在转圈查不出来数据&#xff0c;跟我反馈&#xff0c;我也是很积极的去看有什么问题&#xff0c;我以为就是比较常见的问题吧&#xff0c;当我看的时候觉得很奇怪。 有一个分页的接口其实有很多的…

LSB 题解

今天来刷一道Misc的题目&#xff0c;LSB原理进行图片隐写 LSB原理 LSB是一种利用人类视觉的局限性设计的幻术 PNG和BMP图片中的图像像素一般是由RGB(RED红 GREEN绿 BLUE蓝)三原色组成 记住&#xff0c;JPG图片是不适合使用LSB隐写的&#xff0c;JPG图片对像数进行了有损压缩…

Android逆向之旅—反编译利器Apktool使用教程

apktool下载软件首先下载apktool.bat和apktool.jar官网地址&#xff1a;https://ibotpeaches.github.io/Apktool/install/配置环境变量具体的apktool命令自行百度apktool 解包与打包解包&#xff1a; apktool d xxx.apk打包&#xff1a; apktool b xxx1.jadx安装与使用下载exe或…

C/C++开发,无可避免的内存管理(篇五)-c++与垃圾回收.水中捞月

一、垃圾回收机制 虽然智能指针帮助开展者简化了堆内存回收问题&#xff0c;但是它需要开发者显式声明&#xff0c;需要使用时判断等&#xff0c;还是不够便捷。而像java、Python、C#等开发语言直接支持垃圾回收机制。程序开发上&#xff0c;通常会将不再使用或没有任何指针指向…

译文《Learning to Drive in a Day》

摘要——我们展示了深度强化学习在自动驾驶中的首次应用。从随机初始化的参数中&#xff0c;我们的模型能够使用单个单眼图像作为输入&#xff0c;在少数训练集中学习车道跟随策略。我们提供一个通用且易于获得的奖励&#xff1a;车辆在没有安全驾驶员控制的情况下行驶的距离。…

numpy常用操作

文章目录1 numpy库2 数组对象 ndarray2.1 数组对象的创建2.1.1 利用array函数创建ndarray对象2.1.2 np.ones()和np.zeros()函数2.1.3 np.random.rand()函数2.1.4 np.arange()函数2.1.5 np.linspace()函数2.1.6 np.empty()函数2.2 ndarray对象常用属性2.3 ndarray常用操作2.3.1 …

SkyWalking简介和安装

APM系统 早期的监控系统功能比较单一&#xff0c;主要以监控CPU、内存、网络、I/O等基础设置为主&#xff08;cacti、nagios&#xff09; 后来随着中间件技术的不断发展&#xff0c;监控系统也开始监控缓存、数据库、MQ等各种基础组件的性能&#xff08;zabbix、prommethus&a…

马斯克被曝正在“招兵买马”,准备进军AI赛道

知情人士透露&#xff0c;马斯克最近几周接触了人工智能研究人员&#xff0c;打算成立一个新的研究实验室&#xff0c;开发聊天机器人ChatGPT的竞品。 为了开展这项工作&#xff0c;马斯克一直在向Igor Babuschkin抛橄榄枝&#xff0c;这位研究人员曾经在谷歌和OpenAI任职&…

MySQL数据同步至ElasticSearch的相关实现方法

Python&#xff1a; MySQL数据同步到ES集群(MySQL数据库与ElasticSearch全文检索的同步) 通过logstash将mysql数据同步至es中 SpringbootElasticSearch构建博客检索系统-学习笔记01SpringbootElasticSearch构建博客检索系统-学习笔记02P43 43.新闻案例-数据库数据导入到ES中 13…