【lesson53】线程控制
文章目录
- 线程控制
线程控制
线程创建
 代码:
 
 运行代码:
 
 强调一点,线程和进程不一样,进程有父进程的概念,但在线程组里面,所有的线程都是对等关系。
 
 错误检查:
- 传统的一些函数是,成功返回0,失败返回-1,并且对全局变量errno赋值以指示错误。
- pthreads函数出错时不会设置全局变量errno(而大部分其他POSIX函数会这样做)。而是将错误代码通过返回值返回
- pthreads同样也提供了线程内的errno变量,以支持其它使用errno的代码。对于pthreads函数的错误,建议通过返回值业判定,因为读取返回值要比读取线程内的errno变量的开销更小
进程ID和线程ID
 在Linux中,目前的线程实现是Native POSIX Thread Libaray,简称NPTL。在这种实现下,线程又被称为轻量级进程(Light Weighted Process),每一个用户态的线程,在内核中都对应一个调度实体,也拥有自己的进程描述符(task_struct结构体)。
 没有线程之前,一个进程对应内核里的一个进程描述符,对应一个进程ID。但是引入线程概念之后,情况发生了变化,一个用户进程下管辖N个用户态线程,每个线程作为一个独立的调度实体在内核态都有自己的进程描述符,进程和内核的描述符一下子就变成了1:N关系,POSIX标准又要求进程内的所有线程调用
 getpid函数时返回相同的进程ID,如何解决上述问题呢?
 Linux内核引入了线程组的概念。
 
 多线程的进程,又被称为线程组,线程组内的每一个线程在内核之中都存在一个进程描述符(task_struct)与之对应。进程描述符结构体中的pid,表面上看对应的是进程ID,其实不然,它对应的是线程ID;进程描述
 符中的tgid,含义是Thread Group ID,该值对应的是用户层面的进程ID
 
线程异常
 我们之前学到线程一旦异常那么整个进程都会退出,那么真的是如此吗?
 演示:
 代码
#include <iostream>
#include <pthread.h>
#include <unistd.h>void *threadRoutine(void *arg)
{const std::string name = (char *)arg;while (true){std::cout << name << " pid:" << getpid() << "\n"<< std::endl;int a = 100;a /= 0;//除0错误sleep(1);}return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");while (true){std::cout << "main thread pid:" << getpid() << std::endl;sleep(3);}return 0;
}
运行代码:
 
 我们发现线程一旦异常确实会影响到整个进程。
结论:
 1.线程谁先运行与调度器相关
 2.随便哪个线程一旦异常,都可能导致整个进程整体退出
 3.线程在创建并执行的时候,线程也需要进行等待的,如果主线程不等待,也会引起类似于僵尸进程问题,导致内存泄漏。
线程等待
 已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
 创建新的线程不会复用刚才退出线程的地址空间。
 
 调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:
- 如果thread线程通过return返回,value_ ptr所指向的单元里存放的是thread线程函数的返回值。
- 如果thread线程被别的线程调用pthread_ cancel异常终掉,value_ ptr所指向的单元里存放的是常数PTHREAD_CANCELED。
- 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。
- 如果对thread线程的终止状态不感兴趣,可以传NULL给value_ ptr参数。


 参数解释:
 thread:线程id
 retval:输出型参数,下面再解释用处
 pthread_join默认阻塞等待。
 代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>void *threadRoutine(void *arg)
{const std::string name = (char *)arg;int i = 0;while (true){std::cout << name << "runing....." << std::endl;sleep(1);if(i++ == 10){break;}}std::cout << "new thread quit....." << std::endl;return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");pthread_join(tid,nullptr);std::cout << "main thread wait done .... main quit!" << std::endl;return 0;
}
运行代码:
 
 我们知道pthread_create里面有一个回调函数,而回调函数里面有一个返回值我们之前一直返回nullptr
 
 这个返回值,一般是给主线程的,那么主线程该如何获取到?用pthread_join。
 
 pthread_join的第二个参数,是输出型参数,用来获取放回值的。
 代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>void *threadRoutine(void *arg)
{const std::string name = (char *)arg;int i = 0;while (true){std::cout << name << "runing....." << std::endl;sleep(1);if (i++ == 10){break;}}std::cout << "new thread quit....." << std::endl;return (void *)10;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");void *ret = nullptr;pthread_join(tid, &ret);std::cout << "ret: " << (long long)ret << std::endl;std::cout << "main thread wait done .... main quit!" << std::endl;return 0;
}
我们运行的时候会这样
 我们只要在g++后面加-fpermissive即可
g++ -o mythread mythread.cc -std=c++11 -lpthread -fpermissive

 再运行代码:
 
 可以看到,我们成功获取到了返回值。
 我们不仅仅只能返回变量,我们还能返回其它内容。
 代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>void *threadRoutine(void *arg)
{const std::string name = (char *)arg;int i = 0;int *data = new int[10];while (true){std::cout << name << "runing....." << std::endl;sleep(1);data[i] = i;if (i++ == 10){break;}}std::cout << "new thread quit....." << std::endl;return (void *)data;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");void *ret = nullptr;pthread_join(tid, &ret);int *data = (int *)ret;for (int i = 0; i < 10; i++){std::cout << data[i] << " ";}std::cout << std::endl;std::cout << "main thread wait done .... main quit!" << std::endl;return 0;
}
运行结果:
 
 线程终止
 如果需要只终止某个线程而不终止整个进程,可以有三种方法:
- 从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit。
- 线程可以调用pthread_ exit终止自己。
- 一个线程可以调用pthread_ cancel终止同一进程中的另一个线程。
 能不能用exit终止线程呢?
代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>void *threadRoutine(void *arg)
{const std::string name = (char *)arg;int i = 0;int *data = new int[10];while (true){std::cout << name << "runing....." << std::endl;sleep(1);data[i] = i;if (i++ == 10){break;}}std::cout << "new thread quit....." << std::endl;exit(10);return (void *)data;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");void *ret = nullptr;pthread_join(tid, &ret);int *data = (int *)ret;for (int i = 0; i < 10; i++){std::cout << data[i] << " ";}std::cout << std::endl;std::cout << "main thread wait done .... main quit!" << std::endl;return 0;
}
运行结果:
 
 我们发现整个进程都被终止了,因为exit是终止进程的,绝对不要用exit终止线程。
 那么我们如何终止新线程而不影响main线程呢?
 pthread_exit()OS提供的终止线程的函数
 
 
 参数retval就是之前的返回值。
 代码
#include <iostream>
#include <pthread.h>
#include <unistd.h>void *threadRoutine(void *arg)
{const std::string name = (char *)arg;int i = 0;int *data = new int[10];while (true){std::cout << name << "runing....." << std::endl;sleep(1);data[i] = i;if (i++ == 10){break;}}std::cout << "new thread quit....." << std::endl;pthread_exit((void*)data);
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");void *ret = nullptr;pthread_join(tid, &ret);int *data = (int *)ret;for (int i = 0; i < 10; i++){std::cout << data[i] << " ";}std::cout << std::endl;std::cout << "main thread wait done .... main quit!" << std::endl;return 0;
}
运行结果:
 
 我们看到线程终止成功。
线程取消
 

 
 代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>void *threadRoutine(void *arg)
{const std::string name = (char *)arg;while (true){std::cout << name << "runing....." << std::endl;sleep(1);}std::cout << "new thread quit....." << std::endl;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");int count = 3;while (true){std::cout << "main thread pid:" << getpid() << std::endl;if(count++ > 5) break;sleep(2);}pthread_cancel(tid);std::cout << "pthread cancle tid: " << tid << std::endl; void *ret = nullptr;pthread_join(tid, &ret);std::cout << "ret: " << (long long)ret << std::endl;std::cout << "main thread wait done .... main quit!" << std::endl;sleep(5);return 0;
}
运行结果:
 
 我们看到最后main线程确实等待了5秒
 
 然后退出了。
 我们看到其中tid为啥这么大呢?之后再讲解。
 而我们看到线程被取消,我们join的时候,退出码是-1.
 而-1其实是:
 
线程ID的探索
 我们之前看到线程ID是一个很大的值
 格式化输出线程ID:
 代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cstdio>void *threadRoutine(void *arg)
{const std::string name = (char *)arg;while (true){std::cout << name << "runing....." << std::endl;sleep(1);}std::cout << "new thread quit....." << std::endl;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");printf("%u,%p\n",tid,tid);int count = 3;while (true){std::cout << "main thread pid:" << getpid() << std::endl;if(count++ > 5) break;sleep(2);}pthread_cancel(tid);std::cout << "pthread cancle tid: " << tid << std::endl; void *ret = nullptr;pthread_join(tid, &ret);std::cout << "ret: " << (long long)ret << std::endl;std::cout << "main thread wait done .... main quit!" << std::endl;sleep(5);return 0;
}
运行结果:
 
 我们看到线程ID值很大,tid的本质是一个地址。
 为什么tid不用Linux中的LWP呢?
 因为目前用的不是Linux自带的创建线程的接口,我们用的是pthread库中的接口。
 我们知道线程共享进程的地址空间
 
 但是线程有自己独立的栈结构,那么如何保证栈区是每一个线程独占的呢?---->原本的栈给main线程使用,而其余线程把共享区当做栈区。所以每个线程的tid就是自己栈区的起始地址
 
 见一见
 
 pthread库时通过clone做到上面的那点。
 
 那么我们如何获取线程的id呢?
 
 代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cstdio>void *threadRoutine(void *arg)
{const std::string name = (char *)arg;while (true){std::cout << name << "runing..... id: " << pthread_self() << std::endl;sleep(1);}std::cout << "new thread quit....." << std::endl;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");int count = 3;while (true){std::cout << "main thread id:" << pthread_self() << std::endl;if(count++ > 5) break;sleep(2);}void *ret = nullptr;pthread_join(tid, &ret);std::cout << "ret: " << (long long)ret << std::endl;std::cout << "main thread wait done .... main quit!" << std::endl;sleep(5);return 0;
}
运行代码:
 
 我们看到我们获取到了不同的线程id
大部分线程的代码是共享的!
 一个小实验:
 代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cstdio>int g_val = 0;
void *threadRoutine(void *arg)
{const std::string name = (char *)arg;while(true){std::cout << name << " g_val: " << g_val << " &g_val" << &g_val << std::endl;g_val++;sleep(1);}}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");while(true){std::cout << "main thread g_val: " << g_val << " &g_val" << &g_val << std::endl;sleep(1);}return 0;
}
运行结果:
 
 我们看到g_val被大家所共享,大家都可以看到g_val,一个线程对其进程改变,其它线程都看的到。
 那么如果线程想要自己是私有的变量呢?该如何?
 只要在变量前加__thread即可。
 代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cstdio>__thread int g_val = 0;
void *threadRoutine(void *arg)
{while(true){std::cout << (char*)arg << ": "<< g_val << " &: " << &g_val << std::endl;g_val++;sleep(1);}
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");while(true){std::cout << "main thread: " << g_val << " &: " << &g_val << std::endl;sleep(1);}return 0;
}
运行代码:
 
 这里运行的时候是并行执行的所以会看不清,但是我们也能看到,两个变量的地址不一样的。
__thread:修饰全局变量,带来的结果就是让每一个线程各自拥有一个全局变量---->线程的就不存储。
我们之前学过进程替换,如果线程进行进程替换会如何?
 代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cstdio>__thread int g_val = 0;
void *threadRoutine(void *arg)
{execl("/bin/ls","ls",nullptr);while(true){std::cout << (char*)arg << ": "<< g_val << " &: " << &g_val << std::endl;g_val++;sleep(1);}}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");while(true){std::cout << "main thread: " << g_val << " &: " << &g_val << std::endl;sleep(1);}return 0;
}
运行结果:
 
 我们看到ls确实被执行了,但是整个进程的代码都被替换掉了。
分离线程
 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏。
 如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
测试代码:
#include <iostream>
#include <pthread.h>
#include <unistd.h>
#include <cstdio>
#include <cerrno>
#include <cstring>__thread int g_val = 0;
void *threadRoutine(void *arg)
{pthread_detach(pthread_self());while(true){std::cout << (char*)arg << ": "<< g_val << " &: " << &g_val << std::endl;g_val++;sleep(1);}
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void *)"thread 1");while(true){std::cout << "main thread: " << g_val << " &: " << &g_val << std::endl;sleep(1);break;}int n = pthread_join(tid,nullptr);std::cout << "n:" << n << " errstring: " << strerror(n) << std::endl;return 0;
}
运行结果:
 
 我们看到join异常进程直接退出。
所以线程分离后线程异常也会影响整个进程
C++语言提供的线程,而语言级别的线程库必须调用原生线程库---->本质是对原生线程库的封装
 代码:
 
 运行:
 
 进程线程间的互斥相关背景概念
 临界资源:多线程执行流共享的资源就叫做临界资源
 临界区:每个线程内部,访问临界自娱的代码,就叫做临界区
 互斥:任何时刻,互斥保证有且只有一个执行流进入临界区,访问临界资源,通常对临界资源起保护作用
 原子性(后面讨论如何实现):不会被任何调度机制打断的操作,该操作只有两态,要么完成,要么未完成
如果多个线程访问同一个全局变量,并对它进行数据计算,多线程会互相影响吗?
 测试代码:
 抢票代码
#include <iostream>
#include <thread>
#include <pthread.h>
#include <unistd.h>
#include <cstdio>
#include <cerrno>
#include <cstring>int tickets = 10000;
void *GetTickets(void *args)
{while (true){if (tickets > 0){usleep(1000);printf("%p : %d\n", pthread_self(), tickets);tickets--;}else{break;}}return nullptr;
}int main()
{pthread_t t1;pthread_t t2;pthread_t t3;pthread_create(&t1, nullptr, GetTickets, nullptr);pthread_create(&t2, nullptr, GetTickets, nullptr);pthread_create(&t3, nullptr, GetTickets, nullptr);pthread_join(t1, nullptr);pthread_join(t2, nullptr);pthread_join(t3, nullptr);return 0;
}
运行结果:
 
 我们发现票抢到-1了,这肯定是错的!
 每次运行的结果都不一定一样:
 
 所以tickets在并发访问的时候,导致了我们数据不一致的问题。之后再解决这个歌问题。
相关文章:
 
【lesson53】线程控制
文章目录 线程控制 线程控制 线程创建 代码: 运行代码: 强调一点,线程和进程不一样,进程有父进程的概念,但在线程组里面,所有的线程都是对等关系。 错误检查: 传统的一些函数是,成功返回0&…...
 
TypeScript(一):TypeScript基本理解
TypeScript基本理解 为什么使用TS JavaScript发展至今,没有进行数据类型的验证而我们知道,在编程阶段,错误发现的越早越好而TS就解决了JS的这个问题 认识TypeScript TypeScript是拥有类型的JavaScript超级,它可以编译成普通、…...
 
C语言—指针
碎碎念:做指针题的时候我仿佛回到了原点,总觉得目的是为了把框架搭建起来,我胡说的哈31 1.利用指针变量将一个数组中的数据反向输出。 /*1.利用指针变量将一个数组中的数据反向输出。*/#include <stdio.h> #include <time.h> #include <…...
 
c++作业
Shell中的函数(先调用后使用的原则)(没有申明) (Function) 函数名(有没有参数根据调用格式)(不能写任何内容) { 函数体 Return 返回值 } 函数名 ----》…...
什么是tomcat?tomcat是干什么用的?
前言 Tomcat是一个开源的、轻量级的应用服务器,是Apache软件基金会的一个项目。它实现了Java Servlet、JavaServer Pages(JSP)和Java Expression Language(EL)等Java技术,用于支持在Java平台上运行的动态W…...
 
中科院一区论文复现,改进蜣螂算法,Fuch映射+反向学习+自适应步长+随机差分变异,MATLAB代码...
本期文章复现一篇发表于2024年来自中科院一区TOP顶刊《Energy》的改进蜣螂算法。 论文引用如下: Li Y, Sun K, Yao Q, et al. A dual-optimization wind speed forecasting model based on deep learning and improved dung beetle optimization algorithm[J]. Ener…...
C# 如何实现一个事件总线
EventBus(事件总线)是一种用于在应用程序内部或跨应用程序组件之间进行事件通信的机制。 它允许不同的组件通过发布和订阅事件来进行解耦和通信。在给定的代码片段中,我们可以看到一个使用C#实现的Event Bus。它定义了一些接口和类来实现事件…...
 
Python学习路线图
防止忘记,温故知新 进阶路线...
作业2.14
chgrp: 只能修改文件的所属组 chgrp 新的组 文件名 要求:修改的目标组已经存在 chown: chown 新的用户名 文件名 sudo chown root :1 将文件1的所属组用户和所属组用户都改为root sudo chown root:ubuntu 1 将文件1的所属用户…...
基于python+django+mysql的小区物业管理系统
该系统是基于pythondjango开发的小区物业管理系统。适用场景:大学生、课程作业、毕业设计。学习过程中,如遇问题可以在github给作者留言。主要功能有:业主管理、报修管理、停车管理、资产管理、小区管理、用户管理、日志管理、系统信息。 演示…...
控制与状态机算法
控制与状态机算法是计算机科学、电子工程和自动化领域中常用的一种设计工具,它用来描述一个系统的行为,该系统在不同时间点可以处于不同的状态,并且其行为取决于当前状态以及输入的信号或事件。状态机算法的核心概念包括: 状态(State):系统的任何可能配置。每个状态代表…...
sql常用语句小结
创建表: create table 表名( 字段1 字段类型 【约束】【comment 字段1注释】, //【】里面的东西可以不用加上去 字段2 字段类型 【约束】【comment 字段2注释】 )【comment 表注释】 约束:作用于表中字段上的规则…...
 
云计算基础-虚拟机迁移原理
什么是虚拟机迁移 虚拟机迁移是指将正在运行的虚拟机实例从一个物理服务器(或主机)迁移到另一个物理服务器(或主机)的过程,而不会中断虚拟机的运行。 虚拟机拟机迁移分类虚 热迁移:开机状态下迁移 冷迁…...
 
云计算基础-云计算概念
云计算定义 云计算是一种基于互联网的计算方式,通过这种计算方式,共享的软硬件资源和信息可以按需提供给计算机和其他设备。云计算依赖资源共享以达成规模经济,类似基础设置(如电力网)。 云计算最基本的概念就是云加端,我们有一个…...
 
如何将阿里云服务器迁移
📑前言 本文主要是如何将阿里云服务器迁移实现数据转移的文章,如果有什么需要改进的地方还请大佬指出⛺️** 🎬作者简介:大家好,我是青衿🥇 ☁️博客首页:CSDN主页放风讲故事 🌄每日…...
 
如何将本地的python项目部署到linux服务器中
大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂 。 前言 本地写好的python项目,如何部署在服务器上运行呢?今天,我们就来抽一点点时间来看看。(网上找的资料,大部分都囫囵吞枣的…...
 
每日五道java面试题之java基础篇(五)
目录: 第一题. final、finally、finalize 的区别?第二题. 和 equals 的区别?第三题.hashCode 与 equals?第四题. Java 是值传递,还是引⽤传递?第五题 深拷贝和浅拷贝? 第一题. final、finally、finalize 的…...
HiveSQL——用户行为路径分析
注:参考文档: SQL之用户行为路径分析--HQL面试题46【拼多多面试题】_路径分析 sql-CSDN博客文章浏览阅读2k次,点赞6次,收藏19次。目录0 问题描述1 数据分析2 小结0 问题描述已知用户行为表 tracking_log, 大概字段有&…...
专利的申请
申请发明或者实用新型专利的,应当提交请求书、说明书及其摘要和权利要求书等文件。 请求书应当写明发明或者实用新型的名称,发明人或者设计人的姓名,申请人姓名或者名称、地址,以及其他事项。 说明书应当对发明或者实用新型作出清…...
 
嵌入式学习 C++ Day5、6
嵌入式学习 C Day5、6 一、思维导图 二、作业 1.以下是一个简单的比喻,将多态概念与生活中的实际情况相联系: 比喻:动物园的讲解员和动物表演 想象一下你去了一家动物园,看到了许多不同种类的动物,如狮子、大象、猴…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
 
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
 
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
 
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
 
企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
