Linux C/C++编程的线程结束
【图书推荐】《Linux C与C++一线开发实践(第2版)》_linux c与c++一线开发实践pdf-CSDN博客
《Linux C与C++一线开发实践(第2版)(Linux技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com)
Linux系统与编程技术_夏天又到了的博客-CSDN博客
Linux C/C++编程的线程创建-CSDN博客
线程安全退出是编写多线程程序时一个重要的事项。在Linux下,线程的结束通常由以下原因所致:
(1)在线程函数中调用pthread_exit函数。
(2)线程所属的进程结束了,比如进程调用了exit。
(3)线程函数执行结束后返回(return)了。
(4)线程被同一进程中的其他线程通知结束或取消。
第1种方式,与Windows下的线程退出函数ExitThread不同,pthread_exit不会导致C++对象被析构,所以可以放心使用。第2种方式最好不用,因为线程函数如果有C++对象,则C++对象不会被销毁。第3种方式推荐使用,线程函数执行到return后结束是最安全的方式,尽量将线程设计成这样的形式。第4种方式通常用于其他线程要求目标线程结束运行的情况,比如目标线程中执行一个耗时的复杂科学计算,但用户等不及想中途停止它,此时就可以向目标线程发送取消信号。其实,(1)和(3)属于线程自己主动终止,(2)和(4)属于被动终止,就是自己并不想终止,但外部线程希望自己终止。
一般情况下,进程中各个线程的运行是相互独立的,线程的终止并不会相互通知,也不会影响其他的线程。对于可连接线程,它终止后,所占用的资源并不会随着线程的终止而归还系统,而是仍为线程所在的进程持有,可以调用pthread_join函数来同步并释放资源(这一点前面已经讲过了,这里又讲一遍,希望读者能记住)。
1. 线程主动终止
线程主动终止一般是指线程函数中使用了return语句或调用了pthread_exit函数。函数pthread_exit声明如下:
void pthread_exit(void *retval);
其中,参数retval就是线程退出的时候返回给主线程的值。注意,线程函数的返回类型是void*。另外,在main线程中调用“pthread_exit(NULL);”的时候,将结束main线程,但进程并不立即退出。
下面来看一个线程主动终止的例子。
【例8.12】线程终止并得到线程的退出码
(1)打开Visual Studio Code,新建一个test.cpp文件,在test.cpp中输入代码:
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>#define PTHREAD_NUM 2void *thrfunc1(void *arg) // 第一个线程函数
{static int count = 1; // 这里需要的是静态变量pthread_exit((void*)(&count)); // 通过pthread_exit结束线程
}
void *thrfunc2(void *arg)
{static int count = 2;return (void *)(&count); // 线程函数返回
}int main(int argc, char *argv[])
{pthread_t pid[PTHREAD_NUM]; // 定义两个线程idint retPid;int *pRet1; // 注意这里是指针int * pRet2;if ((retPid = pthread_create(&pid[0], NULL, thrfunc1, NULL)) != 0) // 创建第1个线程{perror("create pid first failed");return -1;}if ((retPid = pthread_create(&pid[1], NULL, thrfunc2, NULL)) != 0) // 创建第2个线程{perror("create pid second failed");return -1;}if (pid[0] != 0){pthread_join(pid[0], (void**)& pRet1); // 注意pthread_join的第2个参数的用法printf("get thread 0 exitcode: %d\n", * pRet1); // 打印线程返回值}if (pid[1] != 0){pthread_join(pid[1], (void**)& pRet2);printf("get thread 1 exitcode: %d\n", * pRet2); // 打印线程返回值}return 0;
}
(2)上传test.cpp到Linux,在终端下输入命令g++ -o test test.cpp -lpthread,其中pthread是线程库的名字,然后运行test,运行结果如下:
[root@localhost Debug]# ./testget thread 0 exitcode: 1get thread 1 exitcode: 2
从这个例子可以看到,线程返回值有两种方式,一种是调用函数pthread_exit,另一种是直接return。此外,这个例子中用了不少强制转换,这里要稍微啰唆一下,首先看函数thrfunc1中的最后一句pthread_exit((void*)(&count));,我们知道pthread_exit函数的参数类型为void *,因此只能通过指针的形式传递出去,故先把整型变量count转换为整型指针,即&count,&count为int*类型,这个时候再与void*匹配,需要进行强制转换,也就是代码中的(void*)(&count);。函数thrfunc2中的return关键字返回值的时候,同样也需要进行强制类型的转换,线程函数的返回类型是void*,那么对于count整型变量来说,必须转换为void型的指针类型(void*),因此有 (void*)((int*)&count);。
介绍完了返回的情况,我们再来介绍一下接收。对于接收返回值的函数pthread_join来说,它有两个作用,其一是等待线程结束,其二是获取线程结束时的返回值。pthread_join的第2个参数类型是void**二级指针,那么我们就把整型指针pRet1的地址(int**类型)赋给它,再显式地转换为void**即可。
要注意一点,返回整数数值的时候使用了static关键字,这是因为必须确定返回值的地址是不变的。如果不用static,则对于count变量而言,以内存上来讲,属于在栈区开辟的变量,那么在调用结束的时候,必然是释放内存空间的,相对而言,这时候就没办法找到count所代表内容的地址空间。这就是为什么很多人在看到swap交换函数的时候,写成swap(int,int)是没有办法进行交换的。因此,如果我们需要修改传过来的参数,就必须使用这个参数的地址,或者一个变量本身是不变的内存地址空间,这样才可以进行修改,否则修改失败或者返回值是随机值。而把返回值定义成静态变量,这样线程结束时,其存储单元依然存在,这样做main线程中可以通过指针引用到它的值,并打印出来。读者可以试试不用静态变量,结果必将不同。还可以试着返回一个字符串,这样比返回一个整数更加简单明了。
2. 线程被动终止
一个线程可能在执行一项耗时的计算任务,用户可能没耐心等待,希望结束该线程。此时线程就要被动终止了。如何被动终止呢?一种方法是在同进程的另一个线程中通过函数pthread_kill发送信号给要终止的线程,目标线程收到信号后再退出。另一种方法是在同进程的其他线程中通过函数pthread_cancel来取消目标线程的执行。我们先来看看pthread_kill。它是向线程发送信号的函数,注意它不是杀死(kill)线程,而是向线程发信号。因此,线程之间交流信息可以用这个函数。需要注意的是,接收信号的线程必须先用sigaction函数注册该信号的处理函数。函数pthread_kill声明如下:
int pthread_kill(pthread_t threadId, int signal);
其中,参数threadId是接收信号的线程的ID;signal是信号,通常是一个大于0的值,如果等于0,就用来探测线程是否存在。如果函数执行成功就返回0,否则返回错误码,如ESRCH表示线程不存在,EINVAL表示信号不合法。
向指定ID的线程发送signal,如果线程代码内不做处理,则按照信号默认的行为影响整个进程。也就是说,如果给一个线程发送了SIGQUIT,但线程却没有实现signal处理函数,则整个进程退出。因此,如果int signal的参数不是0,那么一定要清楚到底要干什么,而且一定要实现线程的信号处理函数,否则就会影响整个进程。
【例8.13】向线程发送请求结束信号
(1)打开Visual Studio Code,新建一个test.cpp文件,在test.cpp中输入代码:
#include <iostream>
#include <pthread.h>
#include <signal.h>
#include <unistd.h> // sleep
using namespace std;static void on_signal_term(int sig) // 信号处理函数
{cout << "sub thread will exit" << endl;pthread_exit(NULL);
}
void *thfunc(void *arg)
{signal(SIGQUIT, on_signal_term); // 注册信号处理函数int tm = 50;while (true) // 死循环,模拟一个长时间计算任务{cout << "thrfunc--left:"<<tm<<" s--" <<endl;sleep(1);tm--; // 每过1秒,tm就减1}return (void *)0;
}int main(int argc, char *argv[])
{pthread_t pid; int res;res = pthread_create(&pid, NULL, thfunc, NULL); // 创建子线程sleep(5); // 让出CPU 5秒,让子线程执行pthread_kill(pid,SIGQUIT);// 5秒结束后,开始向子线程发送SIGQUIT信号,通知它结束pthread_join(pid, NULL); // 等待子线程结束cout << "sub thread has completed,main thread will exit\n";return 0;
}
(2)上传test.cpp到Linux,在终端下输入命令g++ -o test test.cpp -lpthread,其中pthread是线程库的名字,然后运行test,运行结果如下:
[root@localhost cpp98]# ./test
thrfunc--left:50 s--
thrfunc--left:49 s--
thrfunc--left:48 s--
thrfunc--left:47 s--
thrfunc--left:46 s--
sub thread will exit
sub thread has completed,main thread will exit
我们可以看到,子线程在执行的时候,主线程等了5秒后就开始向它发送信号SIGQUIT。在子线程中已经注册了SIGQUIT的处理函数on_signal_term。如果不注册信号SIGQUIT的处理函数,就将调用默认处理,即结束线程所属的进程。读者可以试着把signal(SIGQUIT, on_signal_term);注释掉,再运行一下,就会发现在子线程运行5秒之后整个进程结束了,pthread_kill(pid, SIGQUIT);后面的语句不会再执行。
既然说到了pthread_kill,就顺便讲一种常见应用,即判断线程是否还存活。方法是先发送信号0(一个保留信号),然后判断其返回值,根据返回值就可以知道目标线程是否还存活着。请看下例。
【例8.14】判断线程是否已经结束
(1)打开Visual Studio Code,新建一个test.cpp文件,在test.cpp中输入代码:
#include <iostream>
#include <pthread.h>
#include <signal.h>
#include <unistd.h> // sleep
#include "errno.h" // for ESRCH
using namespace std;void *thfunc(void *arg) // 线程函数
{int tm = 50;while (1) // 如果终止线程,可以在这里改为tm>48或其他{cout << "thrfunc--left:"<<tm<<" s--" <<endl;sleep(1);tm--;}return (void *)0;
}int main(int argc, char *argv[])
{pthread_t pid; int res;res = pthread_create(&pid, NULL, thfunc, NULL); // 创建线程sleep(5);int kill_rc = pthread_kill(pid, 0); // 发送信号0,探测线程是否存活// 打印探测结果if (kill_rc == ESRCH)cout<<"the specified thread did not exists or already quit\n";else if (kill_rc == EINVAL)cout<<"signal is invalid\n";elsecout<<"the specified thread is alive\n";return 0;
}
(2)上传test.cpp到Linux,在终端下输入命令g++ -o test test.cpp -lpthread,其中pthread是线程库的名字,然后运行test,运行结果如下:
[root@localhost cpp98]# g++ -o test test.cpp -lpthread
[root@localhost cpp98]# ./test
thrfunc--left:50 s--
thrfunc--left:49 s--
thrfunc--left:48 s--
thrfunc--left:47 s--
thrfunc--left:46 s--
the specified thread is alive
上面例子中的主线程在休眠5秒后探测子线程是否存活,结果是活着,因为子线程一直在死循环。如果要让探测结果为子线程不存在,可以把死循环改为一个可以跳出循环的条件,比如while(tm>48)。
除了通过函数pthread_kill发送信号来通知线程结束外,还可以通过函数pthread_cancel来取消某个线程的执行。所谓取消某个线程的执行,就是发送取消请求,请求其终止运行。函数pthread_cancel声明如下:
int pthread_cancel(pthread_t thread);
其中,参数thread表示要被取消的线程(目标线程)的ID。如果发送取消请求成功,则函数返回0,否则返回错误码。注意,发送取消请求成功,并不意味着目标线程立即停止运行,即系统并不会马上关闭被取消线程,只有在被取消线程下次调用一些系统函数或C库函数(比如printf),或者调用函数pthread_testcancel(让内核去检测是否需要取消当前线程)时,才会真正结束线程。这种在线程执行过程中检测是否有未响应取消信号的地方叫作取消点。常见的取消点有printf、pthread_testcancel、read/write、sleep等函数调用的地方。如果被取消线程停止成功,就将自动返回常数PTHREAD_CANCELED(这个值是-1),可以通过pthread_join获得这个退出值。
函数pthread_testcancel用于让内核去检测是否需要取消当前线程,声明如下:
void pthread_testcancel(void);
可别小看了pthread_testcancel函数,它可以在线程的死循环中让系统(内核)有机会去检查是否有取消请求过来。如果不调用pthread_testcancel,则函数pthread_cancel取消不了目标线程。下面看两个例子,第一个例子不调用函数pthread_testcancel,无法取消目标线程;第二个例子调用函数pthread_testcancel,取消成功。取消成功的意思是不但取消请求发送成功,而且目标线程停止运行了。
【例8.15】取消线程失败
(1)打开Visual Studio Code,新建一个test.cpp文件,在test.cpp中输入代码:
#include<stdio.h>
#include<stdlib.h>
#include <pthread.h>
#include <unistd.h> // sleep
void *thfunc(void *arg)
{ int i = 1; printf("thread start-------- \n"); while (1) // 死循环i++; return (void *)0;
}
int main()
{ void *ret = NULL; int iret = 0; pthread_t tid; pthread_create(&tid, NULL, thfunc, NULL); // 创建线程sleep(1); pthread_cancel(tid); // 发送取消线程的请求 pthread_join(tid, &ret); // 等待线程结束if (ret == PTHREAD_CANCELED) // 判断是否成功取消线程printf("thread has stopped,and exit code: %d\n", ret); // 打印返回值,应该是-1elseprintf("some error occured");return 0;
}
(2)上传test.cpp到Linux,在终端下输入命令g++ -o test test.cpp -lpthread,其中pthread是线程库的名字,然后运行test,运行结果如下:
[root@localhost cpp98]# ./test
thread start--------
^C
[root@localhost cpp98]#
从运行结果可以看到,程序打印“thread start--------”后就没反应了,我们只能按Ctrl+C快捷键来停止进程。这说明主线程中虽然发送取消请求了,但并没有让子线程停止运行。因为如果停止运行,pthread_join是会返回的,然后会打印其后面的语句。下面我们来改进一下这个程序,在while循环中加一个函数pthread_testcancel。
【例8.16】取消线程成功
(1)打开Visual Studio Code,新建一个test.cpp文件,在test.cpp中输入代码:
#include<stdio.h>
#include<stdlib.h>
#include <pthread.h>
#include <unistd.h> // sleep
void *thfunc(void *arg)
{ int i = 1; printf("thread start-------- \n"); while (1) {i++; pthread_testcancel(); // 让系统测试取消请求} return (void *)0;
}
int main()
{ void *ret = NULL; int iret = 0; pthread_t tid; pthread_create(&tid, NULL, thfunc, NULL); // 创建线程sleep(1); pthread_cancel(tid); // 发送取消线程的请求 pthread_join(tid, &ret); // 等待线程结束if (ret == PTHREAD_CANCELED) // 判断是否成功取消线程printf("thread has stopped,and exit code: %d\n", ret); // 打印返回值,应该是-1elseprintf("some error occured");return 0;
}
(2)上传test.cpp到Linux,在终端下输入命令g++ -o test test.cpp -lpthread其中pthread是线程库的名字,然后运行test,运行结果如下:
[root@localhost cpp98]# g++ -o test test.cpp -lpthread
[root@localhost cpp98]# ./test
thread start--------
thread has stopped,and exit code: -1
可以看到,这个例子取消线程成功了,目标线程停止运行,返回pthread_join,并且得到的线程返回值正是PTHREAD_CANCELED。原因就在于我们在while死循环中添加了函数pthread_testcancel,让系统每次循环都去检查一下有没有取消请求。不使用pthread_testcancel也行,可以在while循环中用sleep函数来代替,但这样会影响while的速度。在实际开发中可以根据具体项目具体分析。
相关文章:
Linux C/C++编程的线程结束
【图书推荐】《Linux C与C一线开发实践(第2版)》_linux c与c一线开发实践pdf-CSDN博客《Linux C与C一线开发实践(第2版)(Linux技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com…...
户口本识别、接口识别、python户口本文字识别集成
文字识别技术是数字化转型中一项重要的信息处理手段,正在改变政府机构、企业及个人用户之间的交互方式。通过先进的OCR(光学字符识别)技术和AI算法的支持,户口本识别不仅简化了信息采集流程,还提高了数据的准确性。 随…...
王佩丰24节Excel学习笔记——第十一讲:Vlookup函数
【以 Excel2010 系列学习,用 Office LTSC 专业增强版 2021 实践】 【本章小技巧】 掌握vlookup使用方法,选区的第一列一定是查询参数条件一。使用通配符查询。vlookup 限 255 位长度。掌握日常使用场景。使用vlookup模糊匹配查询个税 一、使用Vlookup函…...
java全栈day16--Web后端实战(数据库)
一、数据库介绍 二、Mysql安装(自行在网上找,教程简单) 安装好了进行Mysql连接 连接语法:winr输入cmd,在命令行中再输入mysql -uroot -p密码 方法二:winr输入cmd,在命令行中再输入mysql -uroo…...
Upload-labs 靶场(通关攻略)
WebShell 一句话木马: <?php eval($_POST[a])?> <?php system($_POST[a])?> 第一关(删除前端js校验) 删除return checkFile() 就能上传成功 第二关(抓包文件类型校验) BP抓包修改后缀 改为2.php后放行 第三关(上传php同种类型的不…...
【爬虫一】python爬虫基础合集一
【爬虫一】python爬虫基础合集一 1. 网络请求了解1.1. 请求的类型1.2. 网络请求协议1.3. 网络请求过程简单图解1.4. 网络请求Headers(其中的关键字释义):请求头、响应头 2. 网络爬虫的基本工作节点2.1. 了解简单网络请求获取响应数据的过程所涉及要点 1. 网络请求了…...
TRELLIS,一键生成3D模型,图像转3D,微软开源
大家好!今天给大家分享微软最近开源的一个3D模型生成项目——TRELLIS。简单来说就是输入一张图片,它就能自动帮你生成3D模型。这与之前分享的TripoSR项目类似,但是精度和贴图细节比TripoSR要高很多。 好久没关注AI生成3D模型这块,…...
【JavaEE进阶】关于Maven
目录 🌴什么是Maven 🌲为什么要学Maven 🎍创建一个Maven项目 🎄Maven核心功能 🚩项目构建 🚩依赖管理 🎋Maven Help插件 🍀Maven 仓库 🚩本地仓库 Ὢ…...
泷羽sec学习打卡-powershell的灵魂
声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都 与本人无关,切莫逾越法律红线,否则后果自负 关于powshell的那些事儿-玩转powershell 什么是powershell?什么是cmd?powershel…...
利用Map集合设计程序,存储城市和对应等级相关信息
package testmap;import java.util.HashMap; import java.util.Scanner; import java.util.Set;public class TestHashMap6 {public static void main(String[] args) {//1.创建一个Map集合:存储键值对HashMap<String, String> map new HashMap<>();/…...
【数字图像处理】期末综合知识点总结 ver1,灰度图像,图像增强,平滑滤波,锐化滤波,图像复原,图像压缩
关注作者了解更多 我的其他CSDN专栏 过程控制系统 工程测试技术 虚拟仪器技术 可编程控制器 工业现场总线 数字图像处理 智能控制 传感器技术 嵌入式系统 复变函数与积分变换 单片机原理 线性代数 大学物理 热工与工程流体力学 数字信号处理 光电融合集成电路…...
GIN
gin是什么 Gin 是一个用 Go (Golang) 编写的 HTTP Web 框架。 它具有类似 Martini 的 API,但性能比 Martini 快 40 倍。如果你需要极好的性能,使用 Gin 吧。 特点:gin是golang的net/http库封装的web框架,api友好,注…...
Java中通过ArrayList扩展数组
在Java中,ArrayList 是一个动态数组实现,能够根据需要自动调整其大小。与传统的数组不同,ArrayList 不需要预先指定大小,并且提供了许多方便的方法来操作集合中的元素。下面将详细介绍如何使用 ArrayList 进行数组的扩展ÿ…...
2024.12.19总结
今天跑了数据采集和端口扫描,对于容器化和虚拟机的概念不是很理解。然后是北向接口文档,在跟其他人交流时,问原理把我给问住了。在安全这块,要学的的东西很多,确实不是三五个月就能搞定的事。 如今,我要做…...
upload-labs靶场通过攻略
upload-labs靶场 第一关 删除前端js校验 return checkFile() 就能上传成功 第二关(抓包文件类型校验) BP抓包修改后缀 第三关(上传php同种类型的不同后缀) 根据源码发现这关的黑名单不太严谨,我们就可以使用php同种类型的不同后缀 第四关(双上传) 根据源码发现这些后缀的…...
【信息系统项目管理师-论文真题】2017下半年论文详解(包括解题思路和写作要点)
更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 试题一:论信息系统项目的安全管理写作要点解题思路1、访问控制工具与技术2、加密技术3、安全检测与监控工具4、安全策略制定与文档化:5、数据备份与恢复技术试题二:论信息系统项目的成本管理写作要点解题思路…...
运维 mysql、redis 、RocketMQ性能排查
MySQL查看数据库连接数 1. SHOW STATUS命令-查询当前的连接数 MySQL 提供了一个 SHOW STATUS 命令,可以用来查看服务器的状态信息,包括当前的连接数。 SHOW STATUS LIKE Threads_connected;这个命令会返回当前连接到服务器的线程数,即当前…...
使用 rvest 包快速抓取网页数据:从入门到精通
介绍 随着大数据和数据科学的迅速发展,互联网数据的抓取已经成为重要的信息获取手段之一。网页抓取(Web Scraping)可以帮助我们自动化地从网页中提取有价值的数据,应用广泛,包括新闻热点分析、金融数据采集等。在本篇…...
青少年编程与数学 02-004 Go语言Web编程 01课题、Web应用程序
青少年编程与数学 02-004 Go语言Web编程 01课题、Web应用程序 课题摘要:一、Web应用程序二、Web服务器(一)什么是Web服务器(二)Web服务器配置1. 选择服务器软件2. 安装服务器软件3. 配置服务器4. 安全设置5. 部署网站内容6. 测试服…...
MybatisPlus(四)
五、条件构造器和常用接口 1、wapper介绍 Wrapper : 条件构造抽象类,最顶端父类 AbstractWrapper : 用于查询条件封装,生成 sql 的 where 条件 QueryWrapper : 查询条件封装 UpdateWrapper : Update 条件封…...
经典电荷泵/Charge pump——1998.JSSC
电路结构 工作原理 M3 and M4 are the series switches, and M5, M6 switch to the highest voltage. If M5 and M6 are missing, having a large capacitor is of absolute necessity, because must always stay between 2 Vin and 2Vin - Uj to avoid switching on the vert…...
搭建MongoDB
title: 搭建MongoDB date: 2024-11-30 23:30:00 categories: - 服务器 tags: - MongoDB - 大数据搭建MongoDB 环境:Centos 7-2009 1. 创建MongoDB的国内yum源 # 下载Centos7对应最新版7.0.15的安装包 cat >> /etc/yum.repos.d/mongodb.repo << &quo…...
2FA双因子验证技术实现原理
一、背景 随着关注数据安全的意识逐步提升,很多站点都开始强制用户不止使用用户名密码的形式进行登录,还会逐步引导用户开启2FA多因子验证。 Github就已经强制用户使用2FA多因子验证进行账号的登录,现在阿里云、腾讯云等也逐步往这个方向发展…...
boost之bind
简介 用于构造函数对象,其定义在文件bind.hpp中 bind 其底层使用通用的模板类bind_t template<class R, class F, class L> class bind_t { public:typedef bind_t this_type;bind_t(F f, L const & l): f_(f), l_(l) {}#define BOOST_BIND_RETURN re…...
simpleperf生成火焰图的步骤
1. simpleperf 命令抓取.data文件 adb shell simpleperf record --duration 30 -g -p 8734 --trace-offcpu --clockid monotonic -e cpu-clock -o /data/local/tmp/perf.data C:\Users\fadi.su>adb shell simpleperf record --duration 30 -g -p 8734 --trace-offcpu --cl…...
拥有人类情感的AI:未来还是幻想?
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...
EAS的KDTextField 添加回车事件监听
1、控件绑定一个action(可以在ui上配置) 2、因为GUI设置的统一的控件切换键为TAB和ENTER两个,所以需要单独设置这个控件的切换键。 Set<KeyStroke> set new HashSet<KeyStroke>(); set.add(KeyStroke.getKeyStroke(KeyEvent.VK_…...
【Linux】Macvlan介绍及LInux下例子实现
Macvlan Macvlan 是一种网络虚拟化技术,允许在同一物理网络接口上创建多个虚拟网络接口,每个虚拟接口都有自己独立的 MAC 地址。这对于需要在同一物理主机上运行多个网络隔离的应用程序或容器时非常有用。 Macvlan 的特点和用途 独立的 MAC 地址 每个 …...
Kafka Streams 在监控场景的应用与实践
作者:来自 vivo 互联网服务器团队- Pang Haiyun 介绍 Kafka Streams 的原理架构,常见配置以及在监控场景的应用。 一、背景 在当今大数据时代,实时数据处理变得越来越重要,而监控数据的实时性和可靠性是监控能力建设最重要的一环…...
【计算机视觉基础CV】03-深度学习图像分类实战:鲜花数据集加载与预处理详解
本文将深入介绍鲜花分类数据集的加载与处理方式,同时详细解释代码的每一步骤并给出更丰富的实践建议和拓展思路。以实用为导向,为读者提供从数据组织、预处理、加载到可视化展示的完整过程,并为后续模型训练打下基础。 前言 在计算机视觉的深…...
Android实现RecyclerView边缘渐变效果
Android实现RecyclerView边缘渐变效果 1.前言: 是指在RecyclerView中实现淡入淡出效果的边缘效果。通过这种效果,可以使RecyclerView的边缘在滚动时逐渐淡出或淡入,以提升用户体验。 2.Recyclerview属性: 2.1、requiresFading…...
springboot结合AES和国密SM4进行接口加密
api接口加密 1.为什么需要api接口加密呢? 1.防止爬虫 2.防止数据被串改 3.确保数据安全 2.如何实现接口加密呢? 3.我们可以使用哪些加密算法来加密呢? AES 密码学中的高级加密标准(Advanced Encryption Standard,…...
后端项目java中字符串、集合、日期时间常用方法
我这里只介绍了项目中最常用的哈,比如像集合有很多,但我们最常用的就是ArrayList。 然后我这里会以javascript中的字符串、数组的方法为基准来实现,有些方法js和java会有些区别也会介绍 字符串 每次修改 String 对象都会创建一个新的对象,而 StringBuffer 可以在同一个对象…...
前端框架Vue的路由机制
大家好,我是G探险者。 最近在调试前端代码的时候,遇到一个问题。首先我们有一个门户页面,该页面里面有很多的豆腐块,每个豆腐块会配置一个系统的跳转连接。 我的系统就是其中一个豆腐块,我第一次登录进来之后…...
flutter 快速实现侧边栏
首先我们写一个侧边栏工具类,示例如下: import package:flutter/material.dart;class Sidebar extends StatelessWidget {overrideWidget build(BuildContext context) {return Drawer(child: ListView(padding: EdgeInsets.zero,children: <Widget&…...
华为数通最新题库 H12-821 HCIP稳定过人中
以下是成绩单和考试人员 HCIP H12-831 HCIP H12-725 安全中级...
算法训练第二十三天|93. 复原 IP 地址 78. 子集 90. 子集 II
93. 复原 IP 地址--分割 题目 有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 . 分隔。 例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址&…...
JS,递归,处理树形数据组件,模糊查询树形结构数据字段
JS递归如何模糊查询树形结构数据,根据数据中的某一个字段值,模糊匹配 直接拿去使用就行 function filterTreeLabel(arr, label) {let result []arr.forEach((item) > {// if (String(item.POBJECT_NAME).toLowerCase().indexOf(label)!-1) {if (String(item.P…...
前端大数字精度丢失?Choerodon UI 大数字解决方案:精确性与灵活性的结合!
01 引言 在企业项目开发中,数据的精确性是关键。Choerodon UI 的大数字解决方案,通过其高精度计算、数据一致性维护、灵活的数据交互、国际化支持、兼容性保障、定制化格式化等优势,为开发人员提供了一个强大的武器库,以确保在处…...
matlab凸包检测
% 创建一个3D点集 points [1 2 3; 4 5 6; 7 8 9; 10 11 12; 13 14 15]; % 使用convhull函数计算凸包 hull convhull(points); % 输出凸包点的索引 disp(Convex Hull Indices:); disp(hull); % 绘制点集和凸包 figure; scatter3(points(:,1), points(:,2), points(:,3),…...
单节点calico性能优化
在单节点上部署calicov3273后,发现资源占用 修改calico以下配置是资源消耗降低 1、因为是单节点,没有跨节点pod网段组网需要,禁用overlay方式网络(ipip,vxlan),使用route方式网络 配置calico-node的环境变量 CALICO_IPV4POOL_I…...
【芯片设计- RTL 数字逻辑设计入门 番外篇 7.1 -- 基于ATE的IC测试原理】
文章目录 ATE 测试概述Opens/Shorts测试Leakage测试AC测试转自:漫谈大千世界 漫谈大千世界 2024年10月23日 23:17 湖北 ATE 测试概述 ATE(Automatic Test Equipment)是用于检测集成电路(IC)功能完整性的自动测试设备。它在半导体产业中扮演着至关重要的角色,主要用于检…...
oracle 导入数据提示跳过表
imp system/orclorcl fileD:\oracle_back.dmp fully showy logD:\oracle_log.log 今天用上面的命令往 oracle 中导入数据出现一个奇怪的问题 就是所有导入的表都提示 正在跳过表XXX 最后提示成功终止导入, 没有出现警告。 最后select一个表也没导入进来 怪哉怪哉!…...
鸿蒙开发(15)案例 排行榜
排行榜 准备图片 定义案例需要的数据模型 创建Models文件, //定义app需要的数据模型export class FruitData{name:string;vote:string;id:string;constructor(id:string,name:string,vote:string,) {this.id idthis.name namethis.vote vote}}排行榜头部 创…...
【Java Web】Axios实现前后端数据异步交互
目录 一、Promise概述 二、Promise基本用法 三、async和await关键字 四、Axios介绍 4.1 Axios基本用法 4.2 Axios简化用法之get和post方法 五、Axios拦截器 六、跨域问题处理 一、Promise概述 axios是代替原生的ajax实现前后端数据交互的一套新解决方案,而…...
SLAAC如何工作?
SLAAC如何工作? IPv6无状态地址自动配置(SLAAC)-常见问题 - 苍然满关中 - 博客园 https://support.huawei.com/enterprise/zh/doc/EDOC1100323788?sectionj00shttps://www.zhihu.com/question/6691553243/answer/57023796400 主机在启动或接口UP后,发…...
微信小程序UI自动化测试实践 !
微信小程序UI自动化测试实践 引言: 随着微信小程序的快速发展,越来越多的企业和开发者开始开发小程序来满足用户的需求。而在开发小程序的过程中,UI自动化测试是一个必不可少的环节,可以帮助开发者减少人工测试的工作量ÿ…...
代码随想录-笔记-其七
我们来到了贪心算法的章节。 贪心算法和其他部分不太一样的是,他更多的是突出一种思路:通过求局部最优解来求全局最优解。因为只是一个大的思想逻辑,针对不同题型总是有不同的解决方案,所以贪心算法也不想其他算法那样有一个很经…...
react身份证回显
1. 处理身份证号的函数 function getAgeSexAndBirthdate(idCard: string): { sex: 男 | 女 | null; birthdate: Date | null } {if (idCard.length ! 18) {console.error(身份证号码必须是18位。);return { sex: null, birthdate: null };}// 提取出生年月日const year parse…...
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
大家好,今天,我们将讨论 Hibernate 和 JPA 架构。 在开始我们的文章之前,我想回答一个重要的问题:为什么我们需要使用 Hibernate、Eclipse Link、EF core 等 ORM 工具? 事实上,这是一个非常好的问题。我们…...