嵌入式Linux应用开发-基础知识-第十九章驱动程序基石①

嵌入式Linux应用开发-基础知识-第十九章驱动程序基石①

  • 第十九章 驱动程序基石①
    • 19.1 休眠与唤醒
      • 19.1.1 适用场景
      • 19.1.2 内核函数
        • 19.1.2.1 休眠函数
        • 19.1.2.2 唤醒函数
      • 19.1.3 驱动框架
      • 19.1.4 编程
        • 19.1.4.1 驱动程序关键代码
        • 19.1.4.2 应用程序
      • 19.1.5 上机实验
        • 19.1.6 使用环形缓冲区改进驱动程序
    • 19.2 POLL机制
      • 19.2.1 适用场景
      • 19.2.2 使用流程
      • 19.2.3 驱动编程
      • 19.2.4 应用编程
      • 19.2.5 现场编程
      • 19.2.6 上机实验
      • 19.2.7 POLL机制的内核代码详解
        • 19.2.7.1 sys_poll函数
        • 19.2.7.2
        • 19.2.7.3

第十九章 驱动程序基石①

在这里插入图片描述

19.1 休眠与唤醒

19.1.1 适用场景

在前面引入中断时,我们曾经举过一个例子:
在这里插入图片描述

妈妈怎么知道卧室里小孩醒了?
① 时不时进房间看一下:查询方式
简单,但是累
② 进去房间陪小孩一起睡觉,小孩醒了会吵醒她:休眠-唤醒
不累,但是妈妈干不了活了
③ 妈妈要干很多活,但是可以陪小孩睡一会,定个闹钟:poll方式 要浪费点时间,但是可以继续干活。
妈妈要么是被小孩吵醒,要么是被闹钟吵醒。
④ 妈妈在客厅干活,小孩醒了他会自己走出房门告诉妈妈:异步通知 妈妈、小孩互不耽误

当应用程序必须等待某个事件发生,比如必须等待按键被按下时,可以使用“休眠-唤醒”机制:
① APP调用 read等函数试图读取数据,比如读取按键;
② APP进入内核态,也就是调用驱动中的对应函数,发现有数据则复制到用户空间并马上返回; ③ 如果 APP在内核态,也就是在驱动程序中发现没有数据,则 APP休眠;
④ 当有数据时,比如当按下按键时,驱动程序的中断服务程序被调用,它会记录数据、唤醒 APP;
⑤ APP继续运行它的内核态代码,也就是驱动程序中的函数,复制数据到用户空间并马上返回。

驱动中有数据时,下图中红线就是 APP1的执行过程,涉及用户态、内核态:
在这里插入图片描述

驱动中没有数据时,APP1在内核态执行到 drv_read时会休眠。所谓休眠就是把自己的状态改为非RUNNING,这样内核的调度器就不会让它运行。当按下按键,驱动程序中的中断服务程序被调用,它会记录数据,并唤醒 APP1。所以唤醒就是把程序的状态改为 RUNNING,这样内核的调度器有合适的时间就会让它运行。当 APP1再次运行时,就会继续执行 drv_read中剩下的代码,把数据复制回用户空间,返回用户空间。APP1的执行过程如下图的红色实线所示,它被分成了 2段:
在这里插入图片描述

值得注意的是,上面 2个图中红线部分都属于 APP1的“上下文”,或者这样说:红线所涉及的代码,都是 APP1调用的。但是按键的中断服务程序,不属于 APP1的“上下文”,这是突如其来的,当中断发生时,APP1正在休眠呢。
在 APP1的“上下文”,也就是在 APP1的执行过程中,它是可以休眠的。
在中断的处理过程中,也就是 gpio_key_irq的执行过程中,它不能休眠:“中断”怎么能休眠?“中断”休眠了,谁来调度其他 APP啊?
所以,请记住:在中断处理函数中,不能休眠,也就不能调用会导致休眠的函数。

19.1.2 内核函数

19.1.2.1 休眠函数

参考内核源码:include\linux\wait.h。
在这里插入图片描述

比较重要的参数就是:
① wq:waitqueue,等待队列
休眠时除了把程序状态改为非 RUNNING之外,还要把进程/进程放入 wq中,以后中断服务程序
要从 wq中把它取出来唤醒。
没有 wq的话,茫茫人海中,中断服务程序去哪里找到你?
② condition
这可以是一个变量,也可以是任何表达式。表示“一直等待,直到 condition为真”。

19.1.2.2 唤醒函数

参考内核源码:include\linux\wait.h。
在这里插入图片描述

19.1.3 驱动框架

驱动框架如下:
在这里插入图片描述

要休眠的线程,放在 wq队列里,中断处理函数从 wq队列里把它取出来唤醒。 所以,我们要做这几件事:
① 初始化 wq队列
② 在驱动的 read函数中,调用 wait_event_interruptible:
它本身会判断 event是否为 FALSE,如果为 FASLE表示无数据,则休眠。
当从 wait_event_interruptible返回后,把数据复制回用户空间。
③ 在中断服务程序里:
设置 event为 TRUE,并调用 wake_up_interruptible唤醒线程。

19.1.4 编程

使用 GIT命令载后,源码位于这个目录下:

01_all_series_quickstart\ 
05_嵌入式 Linux驱动开发基础知识\source\ 
06_gpio_irq\ 02_read_key_irq\ 和 03_read_key_irq_circle_buffer 

03_read_key_irq_circle_buffer使用了环型缓冲区,可以避免按键丢失。

19.1.4.1 驱动程序关键代码

02_read_key_irq\gpio_key_drv.c中,要先定义“wait queue”:

41 static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait); 

在驱动的读函数里调用 wait_event_interruptible:

44 static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) 
45 { 
46      //printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); 
47      int err; 
48 
49      wait_event_interruptible(gpio_key_wait, g_key); 
50      err = copy_to_user(buf, &g_key, 4); 
51      g_key = 0; 
52 
53      return 4; 
54 } 

第 49行并不一定会进入休眠,它会先判断 g_key是否为 TRUE。
执行到第 50行时,表示要么有了数据(g_key为 TRUE),要么有信号等待处理(本节课程不涉及信号)。
假设 g_key等于 0,那么 APP会执行到上述代码第 49行时进入休眠状态。它被谁唤醒?被控制的中断服务程序:

64 static irqreturn_t gpio_key_isr(int irq, void *dev_id) 
65 { 
66      struct gpio_key *gpio_key = dev_id; 
67      int val; 
68      val = gpiod_get_value(gpio_key->gpiod); 
69 
70 
71      printk("key %d %d\n", gpio_key->gpio, val); 
72      g_key = (gpio_key->gpio << 8) | val; 
73      wake_up_interruptible(&gpio_key_wait); 
74 
75      return IRQ_HANDLED; 
76 } 

上述代码中,第 72行确定按键值 g_key,g_key也就变为 TRUE了。
然后在第 73行唤醒 gpio_key_wait中的第 1个线程。
注意这 2个函数,一个没有使用“&”,另一个使用了“&”:

wait_event_interruptible(gpio_key_wait, g_key); 
wake_up_interruptible(&gpio_key_wait); 
19.1.4.2 应用程序

应用程序并不复杂,调用 open、read即可,代码在 button_test.c中:

25      /* 2. 打开文件 */ 
26      fd = open(argv[1], O_RDWR); 
27      if (fd == -1) 
28      { 
29              printf("can not open file %s\n", argv[1]); 
30              return -1; 
31      } 
32 
33      while (1) 
34      { 
35              /* 3. 读文件 */ 
36              read(fd, &val, 4); 
37              printf("get button : 0x%x\n", val); 
38      } 

在 33行~38行的循环中,APP基本上都是休眠状态。你可以执行 top命令查看 CPU占用率。

19.1.5 上机实验

跟上一节视频类似,需要先修改设备树,请使用上一节视频的设备树文件。
然后安装驱动程序,运行测试程序。

# insmod -f gpio_key_drv.ko 
# ls /dev/xxxxxx_gpio_key 
/dev/xxxxxx_gpio_key 
# ./button_test /dev/xxxxxx_gpio_key  & 
# top 
19.1.6 使用环形缓冲区改进驱动程序

使用 GIT命令载后,源码位于这个目录下:

01_all_series_quickstart\ 
05_嵌入式 Linux驱动开发基础知识\source\ 
06_gpio_irq\ 03_read_key_irq_circle_buffer 

使用环形缓冲区,可以在一定程序上避免按键数据丢失,关键代码如下:

在这里插入图片描述

使用环形缓冲区之后,休眠函数可以这样写:

86      wait_event_interruptible(gpio_key_wait, !is_key_buf_empty()); 87      key = get_key(); 
88      err = copy_to_user(buf, &key, 4); 

唤醒函数可以这样写:

111     key = (gpio_key->gpio << 8) | val; 
112     put_key(key); 
113     wake_up_interruptible(&gpio_key_wait); 

19.2 POLL机制

使用 GIT命令载后,本节源码位于这个目录下:

01_all_series_quickstart\ 
05_嵌入式 Linux驱动开发基础知识\source\ 
06_gpio_irq\ 04_read_key_irq_poll 

19.2.1 适用场景

在前面引入中断时,我们曾经举过一个例子:
在这里插入图片描述
妈妈怎么知道卧室里小孩醒了?
① 时不时进房间看一下:查询方式
简单,但是累
② 进去房间陪小孩一起睡觉,小孩醒了会吵醒她:休眠-唤醒
不累,但是妈妈干不了活了
③ 妈妈要干很多活,但是可以陪小孩睡一会,定个闹钟:poll方式 要浪费点时间,但是可以继续干活。
妈妈要么是被小孩吵醒,要么是被闹钟吵醒。
④ 妈妈在客厅干活,小孩醒了他会自己走出房门告诉妈妈:异步通知 妈妈、小孩互不耽误
使用休眠-唤醒的方式等待某个事件发生时,有一个缺点:等待的时间可能很久。我们可以加上一个超时时间,这时就可以使用 poll机制。
① APP不知道驱动程序中是否有数据,可以先调用 poll函数查询一下,poll函数可以传入超时时间;
② APP进入内核态,调用到驱动程序的 poll函数,如果有数据的话立刻返回;
③ 如果发现没有数据时就休眠一段时间;
④ 当有数据时,比如当按下按键时,驱动程序的中断服务程序被调用,它会记录数据、唤醒 APP; ⑤ 当超时时间到了之后,内核也会唤醒 APP;
⑥ APP根据 poll函数的返回值就可以知道是否有数据,如果有数据就调用 read得到数据

19.2.2 使用流程

妈妈进入房间时,会先看小孩醒没醒,闹钟响之后走出房间之前又会再看小孩醒没醒。 注意:看了 2次小孩!
POLL机制也是类似的,流程如下:
在这里插入图片描述

函数执行流程如上图①~⑧所示,重点从③开始看。假设一开始无按键数据:
③ APP调用 poll之后,进入内核态;
④ 导致驱动程序的 drv_poll被调用:
注意,drv_poll要把自己这个线程挂入等待队列 wq中;假设不放入队列里,那以后发生中断时,中断服务程序去哪里找到你嘛?
drv_poll还会判断一下:有没有数据啊?返回这个状态。
⑤ 假设当前没有数据,则休眠一会;
⑥ 在休眠过程中,按下了按键,发生了中断:
在中断服务程序里记录了按键值,并且从 wq中把线程唤醒了。
⑦ 线程从休眠中被唤醒,继续执行 for循环,再次调用 drv_poll:
drv_poll返回数据状态
⑧ 哦,你有数据,那从内核态返回到应用态吧
⑨ APP调用 read函数读数据
如果一直没有数据,调用流程也是类似的,重点从③开始看,如下:
③ APP调用 poll之后,进入内核态;
④ 导致驱动程序的 drv_poll被调用:
注意,drv_poll要把自己这个线程挂入等待队列 wq中;假设不放入队列里,那以后发生中断时,中断服务程序去哪里找到你嘛?
drv_poll还会判断一下:有没有数据啊?返回这个状态。

⑤ 假设当前没有数据,则休眠一会;
⑥ 在休眠过程中,一直没有按下了按键,超时时间到:内核把这个线程唤醒; ⑦ 线程从休眠中被唤醒,继续执行 for循环,再次调用 drv_poll:
drv_poll返回数据状态
⑧ 哦,你还是没有数据,但是超时时间到了,那从内核态返回到应用态吧
⑨ APP不能调用 read函数读数据
注意几点:
① drv_poll要把线程挂入队列 wq,但是并不是在 drv_poll中进入休眠,而是在调用 drv_poll之后休眠
② drv_poll要返回数据状态
③ APP调用一次 poll,有可能会导致 drv_poll被调用 2次
④ 线程被唤醒的原因有 2:中断发生了去队列 wq中把它唤醒,超时时间到了内核把它唤醒
⑤ APP要判断 poll返回的原因:有数据,还是超时。有数据时再去调用 read函数。

19.2.3 驱动编程

使用 poll机制时,驱动程序的核心就是提供对应的 drv_poll函数。
在 drv_poll函数中要做 2件事:
① 把当前线程挂入队列 wq:poll_wait
APP调用一次 poll,可能导致 drv_poll被调用 2次,但是我们并不需要把当前线程挂入队列 2次。
可以使用内核的函数 poll_wait把线程挂入队列,如果线程已经在队列里了,它就不会再次挂入。
② 返回设备状态:
APP调用 poll函数时,有可能是查询“有没有数据可以读”:POLLIN,也有可能是查询“你有没有空间给我写数据”:POLLOUT。
所以 drv_poll要返回自己的当前状态:(POLLIN | POLLRDNORM) 或 (POLLOUT | POLLWRNORM)。
POLLRDNORM等同于 POLLIN,为了兼容某些 APP把它们一起返回。
POLLWRNORM等同于 POLLOUT ,为了兼容某些 APP把它们一起返回。
APP调用 poll后,很有可能会休眠。对应的,在按键驱动的中断服务程序中,也要有唤醒操作。
驱动程序中 poll的代码如下:

static unsigned int gpio_key_drv_poll(struct file *fp, poll_table * wait) 
{ printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); poll_wait(fp, &gpio_key_wait, wait); return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM; 
} 

19.2.4 应用编程

注意:APP可以调用 poll或 select函数,这 2个函数的作用是一样的。 poll/select函数可以监测多个文件,可以监测多种事件:
在这里插入图片描述

在调用 poll函数时,要指明:
① 你要监测哪一个文件:哪一个 fd
② 你想监测这个文件的哪种事件:是 POLLIN、还是 POLLOUT 最后,在 poll函数返回时,要判断状态。
应用程序代码如下:

struct pollfd fds[1]; 
int timeout_ms = 5000; int ret; 
fds[0].fd = fd; 
fds[0].events = POLLIN; 
ret = poll(fds, 1, timeout_ms); 
if ((ret == 1) && (fds[0].revents & POLLIN)) { read(fd, &val, 4); printf("get button : 0x%x\n", val); 
} 

19.2.5 现场编程

19.2.6 上机实验

19.2.7 POLL机制的内核代码详解

Linux APP系统调用,基本都可以在它的名字前加上“sys_”前缀,这就是它在内核中对应的函数。比如系统调用 open、read、write、poll,与之对应的内核函数为:sys_open、sys_read、sys_write、sys_poll。
对于系统调用 poll或 select,它们对应的内核函数都是 sys_poll。分析 sys_poll,即可理解 poll机制。

19.2.7.1 sys_poll函数

sys_poll位于fs/select.c文件中,代码如下:

SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs) 
{ struct timespec64 end_time, *to = NULL; int ret; 
if (timeout_msecs >= 0) { to = &end_time; poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC, NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC)); } ret = do_sys_poll(ufds, nfds, to); 
…… 

SYSCALL_DEFINE3是一个宏,它定义于 include/linux/syscalls.h,展开后就有 sys_poll函数。 sys_poll对超时参数稍作处理后,直接调用do_sys_poll。

19.2.7.2

do_sys_poll函数
do_sys_poll位于 fs/select.c文件中,我们忽略其他代码,只看关键部分:

int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, struct timespec64 *end_time) 
{ 
…… poll_initwait(&table); fdcount = do_poll(head, &table, end_time); poll_freewait(&table); 
…… 
} 

poll_initwait函数非常简单,它初始化一个 poll_wqueues变量 table:

poll_initwait 
init_poll_funcptr(&pwq->pt, __pollwait); 
pt->qproc = qproc; 

即 table->pt->qproc = __pollwait,__pollwait将在驱动的 poll函数里用到。 do_poll函数才是核心,继续看代码。

19.2.7.3

do_poll函数
do_poll函数位于 fs/select.c文件中,这是 POLL机制中最核心的代码,贴图如下:
在这里插入图片描述
① 从这里开始,将会导致驱动程序的 poll函数被第一次调用。
沿着②③④⑤,你可以看到:驱动程序里的 poll_wait会调用__pollwait函数把线程放入某个队列。
当执行完①之后,在⑥或⑦处,pt->_qproc被设置为 NULL,所以第二次调用驱动程序的 poll时,不会再次把线程放入某个队列里。
⑧ 如果驱动程序的 poll返回有效值,则 count非 0,跳出循环;
⑨ 否则休眠一段时间;当休眠时间到,或是被中断唤醒时,会再次循环、再次调用驱动程序的 poll。
回顾 APP的代码,APP可以指定“想等待某些事件”,poll函数返回后,可以知道“发生了哪些事件”:
在这里插入图片描述

驱动程序里怎么体现呢?在上上一个图中,看②位置处,细说如下:
在这里插入图片描述

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

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

相关文章

89、Redis 的 value 所支持的数据类型(String、List、Set、Zset、Hash)---->Zset 相关命令

本次讲解要点&#xff1a; ** Set相关命令&#xff1a;是指value中的数据类型** 启动redis服务器&#xff1a; 打开小黑窗&#xff1a; C:\Users\JH>e: E:>cd E:\install\Redis6.0\Redis-x64-6.0.14\bin E:\install\Redis6.0\Redis-x64-6.0.14\bin>redis-server.exe …

【算法分析与设计】贪心算法(下)

目录 一、单源最短路径1.1 算法基本思想1.2 算法设计思想1.3 算法的正确性和计算复杂性1.4 归纳证明思路1.5 归纳步骤证明 二、最小生成树2.1 最小生成树性质2.1.1 生成树的性质2.1.2 生成树性质的应用 2.2 Prim算法2.2.1 正确性证明2.2.2 归纳基础2.2.3 归纳步骤2.3 Kruskal算…

【刷题笔记10.2】LeetCode: 罗马数字转整数

LeetCode: 罗马数字转整数 一、题目描述 二、分析 方法一&#xff1a; 将给定字符串s中的"IV", “IX”, “XL”, “XC”, “CD”, “CM” 全部替换为其他字符如&#xff1a;a, b, c, d, e, f 这种&#xff0c;然后就可以遍历累加了。 s s.replace("IV",…

python-切换镜像源和使用PyCharm进行第三方开源包安装

文章目录 前言python-切换镜像源和使用PyCharm进行第三方开源包安装1. 切换镜像源2. 使用PyCharm进行第三方开源包安装 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每…

7.3 调用函数

前言&#xff1a; 思维导图&#xff1a; 7.3.1 函数调用的形式 我的笔记&#xff1a; 函数调用的形式 在C语言中&#xff0c;调用函数是一种常见的操作&#xff0c;主要有以下几种调用方式&#xff1a; 1. 函数调用语句 此时&#xff0c;函数调用独立存在&#xff0c;作为…

ARINC825规范简介

ARINC825规范简介 机载CAN网络通用标准 ARINC825规范全称为机载CAN网络通用标准&#xff08;The General Standardization of CAN for Airborne Use&#xff09;。顾名思义&#xff0c;ARINC825规范是建立在CAN物理网络基础上的高层规范。CAN网络使用共享的双绞电缆传输数据&…

接雨水问题

接雨水问题 问题背景 LeetCode 42. 接雨水 接雨水问题是一个经典的计算雨水滞留量的问题&#xff0c;通常使用柱状图来表示不同高度的柱子。在下雨的情况下&#xff0c;柱子之间的凹陷部分能够存储雨水&#xff0c;问题的目标是计算这些柱子所能接收的雨水总量。 相关知识 …

【人工智能导论】线性回归模型

一、线性回归模型概述 线性回归是利用函数对一个或多个自变量和因变量之间关系进行建模的一种回归分析。简单来说&#xff0c;就是试图找到自变量与因变量之间的关系。 二、线性回归案例&#xff1a;房价预测 1、案例分析 问题&#xff1a;现在要预测140平方的房屋的价格&…

【HUAWEI】单臂路由

目录 ​ &#x1f96e;写在前面 &#x1f96e;2.1、拓扑图 &#x1f96e;2.2、操作思路 &#x1f96e;2.3、配置操作 &#x1f363;2.3.1、LSW4配置 &#x1f363;2.3.2、R2配置 &#x1f363;2.3.3、测试网络 &#x1f990;博客主页&#xff1a;大虾好吃吗的博客 &…

求∑(1,n)⌊k/i⌋∗i

对于[k/i]*i,我们可以分两端&#xff0c;前,最多有段&#xff0c;后边从到n&#xff0c;取值范围为1-&#xff0c;所以最多有段&#xff0c;共2*段。对于每段从i开始&#xff0c;其上界jk/(k/i)&#xff08;维持k/i不变最大范围i-j&#xff09;。 计算[k/i]*i时间复杂度降到级…

十大常见排序算法详解(附Java代码实现和代码解析)

文章目录 十大排序算法⛅前言&#x1f331;1、排序概述&#x1f334;2、排序的实现&#x1f335;2.1 插入排序&#x1f433;2.1.1 直接插入排序算法介绍算法实现 &#x1f433;2.1.2 希尔排序算法介绍算法实现 &#x1f335;2.2 选择排序&#x1f433;2.2.1 选择排序算法介绍算…

在linux下预览markdown的方法,转换成html和pdf

背景 markdown是一种便于编写和版本控制的格式&#xff0c;但却不便于预览——特别是包含表格等复杂内容时&#xff0c;单纯的语法高亮是远远不够的——这样就不能边预览边调整内容&#xff0c;需要找到一种预览方法。 思路 linux下有个工具&#xff0c;叫pandoc&#xff0c…

华为云云耀云服务器L实例评测 | 实例使用教学之简单使用:通过部署宝塔面板可视化管理华为云云耀云服务器

华为云云耀云服务器L实例评测 &#xff5c; 实例使用教学之简单使用&#xff1a;通过部署宝塔面板可视化管理华为云云耀云服务器 介绍华为云云耀云服务器 华为云云耀云服务器 &#xff08;目前已经全新升级为 华为云云耀云服务器L实例&#xff09; 华为云云耀云服务器是什么华为…

【C语言经典100例题-66】(用指针解决)输入3个数a,b,c,按大小顺序输出。

代码&#xff1a; #include<stdio.h> #define _CRT_SECURE_NO_WARNINGS 1//VS编译器使用scanf函数时会报错&#xff0c;所以添加宏定义 swap(p1, p2) int* p1, * p2; {int p;p *p1;*p1 *p2;*p2 p; } int main() {int n1, n2, n3;int* pointer1, * pointer2, * point…

ARM---实现1-100求和任务

.text .globl _start_start:mov r0, #0x1mov r1, #0x1 给r1加一固定1不变mov r2, #0x64 100判断bl sumcmp r1, r2 sum:addcc r1, r1,#0x1 r1自增addcc r0, r0, r1 r0求和movcc pc,lrstop:b stop.end

BI神器Power Query(27)-- 使用PQ实现表格多列转换(3/3)

实例需求&#xff1a;原始表格包含多列属性数据,现在需要将不同属性分列展示在不同的行中&#xff0c;att1、att3、att5为一组&#xff0c;att2、att3、att6为另一组&#xff0c;数据如下所示。 更新表格数据 原始数据表&#xff1a; Col1Col2Att1Att2Att3Att4Att5Att6AAADD…

Hive【Hive(三)查询语句】

前言 今天是中秋节&#xff0c;早上七点就醒了&#xff0c;干啥呢&#xff0c;大一开学后空教室紧缺&#xff0c;还不趁着假期来学校等啥呢。顺便偷偷许个愿吧&#xff0c;希望在明年的这个时候&#xff0c;秋招不知道赶不赶得上&#xff0c;我希望拿几个国奖&#xff0c;蓝桥杯…

火热报名中 | 2天峰会、20+热门议题,AutoESG 2023数智低碳---中国汽车碳管理创新峰会亮点抢先看!

在碳中和的背景下&#xff0c;减碳之风吹遍全球&#xff0c;而汽车行业则由于产业链长、辐射面广、碳排放总量增长快、单车碳强度高的特点&#xff0c;成为各国碳排放管理的监管重点&#xff0c;聚焦汽车业的碳博弈也逐步升级。 2020年&#xff0c;国务院办公厅印发的《新能源…

douyin 六神x-helios / x-medusa解密记录学习

在某音新版本的抓包中&#xff0c;经常会遇到两个熟悉的字段x-helios &#xff0c;x-medusa&#xff0c;它是新版本中风控的重要组成部分。 通常而言&#xff0c;我们可以使用像frida&#xff0c;unidbg来模拟计算出六神参数&#xff0c;比如说我们随便找一个23.9版本生成一个…

K折交叉验证——cross_val_score函数使用说明

在机器学习中&#xff0c;许多算法中多个超参数&#xff0c;超参数的取值不同会导致结果差异很大&#xff0c;如何确定最优的超参数&#xff1f;此时就需要进行交叉验证的方法&#xff0c;sklearn给我们提供了相应的cross_val_score函数&#xff0c;可对数据集进行交叉验证划分…