【Linux】线程Thread
🔥博客主页: 我要成为C++领域大神
🎥系列专栏:【C++核心编程】 【计算机网络】 【Linux编程】 【操作系统】
❤️感谢大家点赞👍收藏⭐评论✍️本博客致力于知识分享,与更多的人进行学习交流
线程概述
线程是进程中的一个执行单元
经典的并发模型,多进程模型,占用大量的内存开销,庞大的进程间调度开销,提供一种开销更小,更轻量级的并发解决方案,多线程技术。
线程在进程中,与进程共享资源和数据,进程是容器,线程是执行单元,进程退出可能导致所有线程退出。
每个进程中都有一个主控线程,还有其他的普通线程,操作系统会给进程分配需要的内存单元。
不支持线程技术的操作系统可以忽略线程概念,进程是调度单位。
多线程操作系统下,进程是内存管理单位,线程才是唯一的调度单元。
线程的CPU分配
Linux操作系统下,线程就是轻量级进程,每个进程分配一个LWP
在Linux操作系统下,所有的调度单位都是进程,淡化线程概念
线程的实现方式
用户线程(User Thread):在用户空间实现的线程,不是由内核管理的线程,是由用户态的线程库来完成线程的管理。可以利用第三方库的形式在不支持线程技术的系统下安装和使用线程,用户级线程的调度开销更小,因为大部分的操作都在用户层完成,无需内核干预
内核线程(Kernel Thread):操作系统中每创建一个线程,系统都会为其创建一个内核对象,此线程系统可以识别支持,会为线程执行资源(时间片)。Control控制器会为每个内核级线程创建内核对象,每个内核级线程都会由CPU进行时间片切换
轻量级进程(LightWeight Process):在内核中来支持用户线程;
进程的蜕化
进程内存资源独占,不与其他人共享,进程是独立的调度单位(无需考虑线程问题)
进程中出现了多个执行单元,讨论考虑线程问题
讨论和分析的蜕化,讨论线程,进程的讨论变为主线程和普通线程的分析和讨论
线程间的共享资源和非共享资源
PCB:共享资源
栈:线程栈空间非共享,每个线程创建后,会分配8MB线程栈
库:库资源共享
堆:共享堆空间
全局资源和静态资源:全局资源共享
代码段:代码段共享
文件描述符表:文件描述符表共享
信号的处理行为(某个线程改变信号行为)对所有线程共享。信号屏蔽字非共享,普通线程拥有独立的屏蔽字,拷贝继承于主线程
TCB:每个线程拥有自己的线程控制块,独立的tid
线程开发相关API接口
NPTL线程库
NPTL线程库是典型的内核级线程库,创建的线程可以被系统标识分配cpu资源(轻量级进程)
native Posix thread library
相关命令
ps aux
进程查看
ps ajx
进程关系查看
ps -eLf
所有线程查看 PID相同的是一组线程
LWP
与 PID
相同的情况表示该进程只有一个线程。
ps -Lf pid
查看某一个进程下的线程
每个线程都会被系统分配lwp 调度编号, 便于系统管理调度线程,但是线程拥有独立的tid,线程id
头文件和函数
#include <pthread.h>
使用线程函数的头文件
pthread_t tid
线程tid类型
pthread_create
创建线程并指定类型pthread_create(pthread_t *tid,NULL,void * (thread_job)(void *),void *arg)
第一个参数是线程id,第二个是线程属性,第三个参数是线程工作地址,第四个参数是线程工作参数。
返回值是err
下面是使用pthread_create
创建线程的简单demo程序,通过PID
和LWP
相同可以看出,这个线程就是主控线程
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <pthread.h>void * thread_job(void *arg)//普通线程的创建
{printf("普通线程被创建,参数为%d\n",*(int*)arg);return NULL;
}int main()
{pthread_t tid;int code=1024;//普通线程都是由主控线程创建的pthread_create(&tid,NULL,thread_job,(void*)&code);printf("普通线程被主控线程创建出来\n");while(1) sleep(1);return 0;
}
在编译时需要链接库
gcc Pthrad_Create.c -lpthread -o app
关于线程函数的错误处理
线程函数出错,会返回错误号(err>0),使用char *errstr=strerror(err)
进行错误判断
下面是打印错误日志的demo程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <pthread.h>void * thread_job(void *arg)//普通线程的创建
{//printf("普通线程被创建,参数为%d\n",*(int*)arg);while(1) sleep(1);return NULL;
}int main()
{pthread_t tid;int code=1024;int flags=0;int err;//普通线程都是由主控线程创建的while(1){if((err=pthread_create(&tid,NULL,thread_job,(void*)&code))>0){printf("thread create failed:%s\n",strerror(err));exit(0);//创建失败,进程退出}else{printf("线程%d成功创建\n",++flags);}}return 0;
}
32位Ubuntu操作系统下,一个进程只能创建381个线程
pthread_self
pthread_tid =pthread_self(void)
成功返回当前线程的id
主线程通过pthread_create创建普通线程,成功传出tid与普通线程自身利用pthread_self()得到的tid值相等但是进程状态不相等,因为pthread_self()获取tid时可以保证当前的有效性,主线程在获取tid的时候,普通线程可能已经退出。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <pthread.h>void * thread_job(void *arg)//普通线程的创建
{printf("普通线程tid %x 创建成功\n",(unsigned int)pthread_self());return NULL;
}int main()
{pthread_t tid;int code=1024;int flags=0;int err;//普通线程都是由主控线程创建的if((err=pthread_create(&tid,NULL,thread_job,(void*)&code))>0){printf("thread create failed:%s\n",strerror(err));exit(0);//创建失败,进程退出}printf("Monster Thread Tid:%x 普通线程Tid:%lx \n",(unsigned int)pthread_self(),tid);while(1) sleep(1);//主控线程还在运行,普通线程已经退出return 0;
}
pthread_join(pthread_t tid,void **retval)
线程回收函数,可以回收线程资源的同时获取线程的返回值。经典的阻塞回收函数,会一致等待普通线程结束后,进行回收。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <pthread.h>void * thread_job(void *arg)//普通线程的创建
{printf("普通线程tid %x 创建成功\n",(unsigned int)pthread_self());return (void*)126;
}int main()
{pthread_t tid;int code=1024;int flags=0;int err;void *revtal=NULL;//普通线程都是由主控线程创建的if((err=pthread_create(&tid,NULL,thread_job,(void*)&code))>0){printf("thread create failed:%s\n",strerror(err));exit(0);//创建失败,进程退出}printf("Monster Thread Tid:%x 普通线程Tid:%lx \n",(unsigned int)pthread_self(),tid);pthread_join(tid,&revtal);printf("Thread Exit Code:%ld\n",(long int)revtal);return 0;
}
可以看到,如果线程工作函数可以正常退出,退出码就是线程工作函数的返回值
pthread_cancel(pthread_t tid)
指定线程tid,取消结束线程
下面是简单的取消一个线程的demo程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <pthread.h>void * thread_job(void *arg)//普通线程的创建
{//printf("普通线程tid %x 创建成功\n",(unsigned int)pthread_self());while(1){printf("进程正在工作。。。\n");sleep(1);}return (void*)129;
}int main()
{pthread_t tid;int code=1024;int flags=0;int err;void *revtal=NULL;//普通线程都是由主控线程创建的if((err=pthread_create(&tid,NULL,thread_job,(void*)&code))>0){printf("thread create failed:%s\n",strerror(err));exit(0);//创建失败,进程退出}printf("Monster Thread Tid:%x 普通线程Tid:%lx \n",(unsigned int)pthread_self(),tid);sleep(5);pthread_cancel(tid);pause();return 0;
}
线程被成功结束,这个进程下只有一个主控线程在工作
当我们对代码稍作修改:
删除线程工作函数中的调用系统函数:
void * thread_job(void *arg)//普通线程的创建
{//printf("普通线程tid %x 创建成功\n",(unsigned int)pthread_self());while(1){}return (void*)129;
}int main()
{pthread_t tid;int code=1024;int flags=0;int err;void *revtal=NULL;//普通线程都是由主控线程创建的if((err=pthread_create(&tid,NULL,thread_job,(void*)&code))>0){printf("thread create failed:%s\n",strerror(err));exit(0);//创建失败,进程退出}printf("Monster Thread Tid:%x 普通线程Tid:%lx \n",(unsigned int)pthread_self(),tid);sleep(5);pthread_cancel(tid);pause(); return 0;
}
结果显示,pthread_cancel
并没有成功取消线程。
这有些类似于信号,信号处理的三个切换条件:系统调用,软件中断,软件异常。而pthread_cancel
取消事件的处理条件,必须有系统调用。
有一个专门为pthread_cancel
提供系统调用的空函数:void pthread_testcancel(void)
,提供一次空的调用。
在线程工作函数加入这个函数再次尝试:
void * thread_job(void *arg)//普通线程的创建
{//printf("普通线程tid %x 创建成功\n",(unsigned int)pthread_self());while(1){pthread_testcancel(void);}return (void*)129;
}int main()
{pthread_t tid;int code=1024;int flags=0;int err;void *revtal=NULL;//普通线程都是由主控线程创建的if((err=pthread_create(&tid,NULL,thread_job,(void*)&code))>0){printf("thread create failed:%s\n",strerror(err));exit(0);//创建失败,进程退出}printf("Monster Thread Tid:%x 普通线程Tid:%lx \n",(unsigned int)pthread_self(),tid);sleep(5);pthread_cancel(tid);pause(); return 0;
}
可以看到只要一个主控线程,普通线程被结束了。
当我们对线程进行取消后,回收一下资源打印退出码看一下:
void * thread_job(void *arg)//普通线程的创建
{//printf("普通线程tid %x 创建成功\n",(unsigned int)pthread_self());while(1){pthread_testcancel(void);}return (void*)129;
}int main()
{pthread_t tid;int code=1024;int flags=0;int err;void *revtal=NULL;//普通线程都是由主控线程创建的if((err=pthread_create(&tid,NULL,thread_job,(void*)&code))>0){printf("thread create failed:%s\n",strerror(err));exit(0);//创建失败,进程退出}printf("Monster Thread Tid:%x 普通线程Tid:%lx \n",(unsigned int)pthread_self(),tid);sleep(5);pthread_cancel(tid);pthread_join(tid,&revtal);printf("Thread Exit Code:%ld\n",(long int)revtal);pause(); return 0;
}
可以看到退出码是-1,所以线程指定退出码时不允许使用-1,保留给pthread_cancel
。
pthread_detach(pthread_t tid)
用于将一个线程设置为分离态线程。
可以通过线程属性,批量创建分离态线程,这些线程诞生即是分离态。
线程有回收态和分离态,这两种状态是互斥的。
若修改线程退出状态,从回收态改为分离态,此操作不可逆,不能将分离线程变为回收态
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <pthread.h>void * thread_job(void *arg)//普通线程的创建
{pthread_detach(pthread_self());while(1){pthread_testcancel();}return (void*)129;
}int main()
{pthread_t tid;int code=1024;int flags=0;int err;void *revtal=NULL;//普通线程都是由主控线程创建的if((err=pthread_create(&tid,NULL,thread_job,(void*)&code))>0){printf("thread create failed:%s\n",strerror(err));exit(0);//创建失败,进程退出}printf("Monster Thread Tid:%x 普通线程Tid:%lx \n",(unsigned int)pthread_self(),tid);if((err=pthread_join(tid,&revtal))>0){printf("join call failed %s\n",strerror(err));}printf("Thread Exit Code:%ld\n",(long int)revtal);pause();return 0;
}
join
和detach
会竞争时间片,所以有时线程以detach
分离态被创建,当线程处于分离态时,无法手动回收,join
执行失败
如果对一个分离态线程进行回收操作,pthread_join
会失效返回。对一个已经处于回收阶段(join已经开始阻塞等待了)的线程设置分离,分离设置失败。
一个自行回收,一个由系统回收,一个可以得到线程退出码,一个无法获取
pthread_exit(void * exitcode)
线程退出函数,结束当前线程,与进程无关,退出码可以被join
获取
线程的退出方式
return 0
主线程结束进程;结束普通线程,返回结果
pthread_cancel
主线程结束,与进程无关
普通进程结束,与进程无关
使用普通线程对主线程进行回收,产生了僵尸级线程
pthread_exit()
主线程结束,与进程无关
普通进程结束,与进程无关
exit()
进程退出,释放所有线程
线程属性
在使用创建线程函数时指定线程类型pthread_create(pthread_t *tid,pthread_attr_t *attr,void * (thread_job)(void *),void *arg)
用第二个参数指定线程属性
pthread_attr_t
线程属性类型,是一个结构体类型
修改线程程属性的操作
使用pthread_attr_getdetachstate
查看线程默认退出属性
使用pthread_attr_getstack
查看栈属性
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <signal.h>
#include <pthread.h>int main()
{int State;void *stack_addr;//栈空间地址size_t stacksize;//栈空间默认大小pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_getdetachstate(&attr,&State);if(State==PTHREAD_CREATE_JOINABLE)printf("Thread Default State is Join\n");elseprintf("Thread Default State is Detach\n");pthread_attr_getstack(&attr,&stack_addr,&stacksize);printf("线程栈地址为%p 栈大小为%d\n",stack_addr,stacksize);return 0;
}
使用pthread_attr_setdetachstate
修改线程默认退出状态为分离态
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <signal.h>
#include <pthread.h>void *thread_job(void * arg)
{}int main()
{int State;void *stack_addr;//栈空间地址size_t stacksize;//栈空间默认大小pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_getdetachstate(&attr,&State);if(State==PTHREAD_CREATE_JOINABLE)printf("Thread Default State is Join\n");elseprintf("Thread Default State is Detach\n");pthread_attr_getstack(&attr,&stack_addr,&stacksize);printf("线程栈地址为%p 栈大小为%d\n",stack_addr,stacksize);pthread_t tid;pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);pthread_create(&tid,&attr,thread_job,NULL);int err=pthread_join(tid,NULL);if(err>0)printf("Join Call Failed:%s\n",strerror(err));return 0;
}
使用pthread_attr_setstacksize
修改默认线程栈大小
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/fcntl.h>
#include <signal.h>
#include <pthread.h>void *thread_job(void * arg)
{}int main()
{int State;void *stack_addr;//栈空间地址size_t stacksize;//栈空间默认大小pthread_attr_t attr;pthread_attr_init(&attr);pthread_attr_getdetachstate(&attr,&State);if(State==PTHREAD_CREATE_JOINABLE)printf("Thread Default State is Join\n");elseprintf("Thread Default State is Detach\n");pthread_attr_getstack(&attr,&stack_addr,&stacksize);printf("线程栈地址为%p 栈大小为%d\n",stack_addr,stacksize);pthread_t tid;pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);stacksize=0x100000;int err;int flags=0;while(1){if((stack_addr=(void*)malloc(stacksize))==NULL){printf("malloc Stack Failed\n");}pthread_attr_setstacksize(&attr,stacksize);if((err=pthread_create(&tid,&attr,thread_job,NULL))>0){printf("Create failed:%s\n",strerror(err));exit(0);}printf("Thread %d 创建成功\n",++flags);}return 0;
}
由结果可知,当将默认大小变小后,32位系统下可以创建的线程数量增加了。
相关文章:

【Linux】线程Thread
🔥博客主页: 我要成为C领域大神🎥系列专栏:【C核心编程】 【计算机网络】 【Linux编程】 【操作系统】 ❤️感谢大家点赞👍收藏⭐评论✍️ 本博客致力于知识分享,与更多的人进行学习交流 线程概述 …...
RAG技术:在自然语言处理中的深度融合与创新
在自然语言处理(NLP)领域,随着技术的不断进步,我们见证了各种创新方法的涌现。其中,检索增强生成(Retrieval-Augmented Generation,简称RAG)技术以其独特的优势,逐渐成为…...
什么是std::bind
2024年6月29日,周日下午 std::bind 是一个C11标准库中的函数,它用于将一个函数或函数对象与特定的参数绑定在一起,生成一个新的函数对象。 std::bind通常和std::function一起使用,因为std::function可以作为一个函数容器来接收st…...

C语言的数据结构:树与二叉树(哈夫曼树篇)
前言 上篇讲完了二叉树,二叉树的查找性能要比树好很多,如平衡二叉树保证左右两边节点层级相差不会大于1,其查找的时间复杂度仅为 l o g 2 n log_2n log2n,在两边层级相同时,其查找速度接近于二分查找。1w条数据&am…...
docker 安装syslog
Syslog-ng是一个可靠、多功能的日志管理系统,用于收集日志并将其转发到指定的日志分析工具。 使用Docker CLI方式搭建 步骤 1: 拉取Syslog-ng镜像 首先,需要从Docker Hub拉取Syslog-ng的官方镜像。 docker pull balabit/syslog-ng:latest 步骤 2: 启动…...

什么是无头浏览器?
简而言之,无头浏览器是没有图形用户界面 (GUI) 的 Web 浏览器。GUI 包括用户与之交互的数字元素,例如按钮、图标和窗口。但是,关于无头浏览器,您需要了解的还有很多。 在本文中,您将了解什么是…...

【面试干货】与的区别:位运算符与逻辑运算符的深入探讨
【面试干货】&与&&的区别:位运算符与逻辑运算符的深入探讨 1、&:位运算符2、&&:逻辑运算符3、&与&&的区别 💖The Begin💖点点关注,收藏不迷路💖 & 和 …...

搭建Renesas R7FA8D1BHECBD-BTB的开发调试环境(DAP-LINK: N32G45XVL-STB)
目录 概述 1 软硬件 1.1 软硬件环境信息 1.2 开发板信息 1.3 调试器信息 2 FSP和KEIL产生测试项目 2.1 FSP生成项目 2.2 Keil中配置 3 硬件连接框图 4 一个测试案例 4.1 功能介绍 4.2 定时器函数 5 测试 搭建Renesas R7FA8D1BHECBD-BTB的开发调试环境(…...

探索人工智能和LLM对未来就业的影响
近年来,人工智能(AI)迅猛发展,引发了人们的兴奋,同时也引发了人们对就业未来的担忧。大型语言模型(LLM)就是最新的例子。这些强大的人工智能子集经过大量文本数据的训练,以理解和生成…...
钓鱼网站原理与攻防
知识点:LAMP平台部署,Web架构分析,钓鱼网站原理与搭建 中间件: 中间件是一种独立的软件,位于客户机和服务器之间,主要用于在网络环境中进行数据的传输和通信。它充当客户端和服务端之间的桥梁,…...

Windows 中 Chrome / Edge / Firefox 浏览器书签文件默认存储路径
1. Chrome 浏览器 按组合键 Win R,打开运行对话框,输入 %USERPROFILE%\AppData\Local\Google\Chrome\User Data\Default或在Chrome 浏览器地址栏输入 chrome://version查看【个人资料路径】 2. Edge 浏览器 按组合键 Win R,打开运行对…...

秋招Java后端开发冲刺——关系型数据库篇(Mysql)
本文介绍关系型数据库及其代表Mysql数据库,并介常见面试题目。 一、数据库概述 1. 数据库(Database, DB):是长期储存在计算机内的、有组织的、可共享的数据集合。 2. 数据库管理系统(Database Management System, D…...

DHCP原理1-单个局域网出现多个DHCP服务器会发生什么
1. 背景 DHCP全称是Dynamic Host Configuration Protocol。其协议标准是RFC1541(已被RFC2131取代),主要实现服务器向客户端动态分配IP地址(如IP地址、子网掩码、网关、DNS)和配置信息。其系统架构是标准的C/S架构。RFC…...
24/06/29(21.1205)程序的编译和链接
源文件 ---> 可执行文件,这一过程要执行的流程: 预处理 编译 汇编 链接 组成每一个程序的每个源文件通过编译过程分别转换成目标代码;每个目标代码由链接器捆绑在一起,形成一个单一而完整的可执行程序;链接器同时也会引入标准函数库中任何被该程序所用到的函数,而且它可以…...
使用Java Executors框架处理并发任务
一、并发与Java Executors框架简介 一、并发编程的重要性 并发编程是现代编程中最重要的概念之一。在更多的核心和更快的处理器出现的今天,如何充分利用这些资源就变得异常重要。并发编程允许你的程序同时处理多个任务,从而使程序更有效地利用系统资源,提高执行效率。 提…...
LeetCode:经典题之144、94、145、102题解及延伸|二叉树的遍历|前中后层序遍历|Morris算法
系列目录 88.合并两个有序数组 52.螺旋数组 567.字符串的排列 643.子数组最大平均数 150.逆波兰表达式 61.旋转链表 160.相交链表 83.删除排序链表中的重复元素 389.找不同 1491.去掉最低工资和最高工资后的工资平均值 896.单调序列 206.反转链表 92.反转链表II 141.环形链表 …...

ONLYOFFICE 桌面编辑器 8.1全新发布,更强大的编辑工具
ONLYOFFICE 8.1 一、什么是ONLYOFFICE?二、怎么安装 ONLYOFFICE 8.1三、主要功能介绍四、总结 一、什么是ONLYOFFICE? ONLYOFFICE 是一款功能强大的办公套件,旨在提供全面的文档、表格和演示文稿编辑解决方案。它集成了文字处理、电子表格和演…...
百日筑基第六天-了解一下Dubbo
百日筑基第六天-了解一下Dubbo Dubbo 是一款高性能、轻量级的开源 WEB 和 RPC 框架。 Dubbo 提供了六大核心能力: 面向接口代理的高性能 RPC 调用。智能容错和负载均衡。服务自动注册和发现。高度可扩展能力。运行期流量调度。可视化的服务治理与运维。 简单来说…...

微机原理 复习
第一章导论 1.3 冯诺依曼体系结构 (1)以二进制形式表示指令和数据 (2)程序和数据事先放在存储器中(预存储) (3)由运算器、控制器、输入设备和输出设备五大部件组成 字长、主频…...
5年工作经验面试经验以及面试题分享
第一家面试题 评价 全是八股文 面试题 MySQL索引类型 索引结构 联合索引可以设置索引类型 不同索引性能差异巨大 基础索引有哪些 B Tree索引和Hash索引 Redis基本数据结构 List是原子的吗 原子性和可见性区别是什么 MySQL的存储过程和视图 MySQL性能优化有哪些 MySQL的存储…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...

对象回调初步研究
_OBJECT_TYPE结构分析 在介绍什么是对象回调前,首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光…...