当前位置: 首页 > news >正文

从0开始linux(39)——线程(2)线程控制

欢迎来到博主的专栏:从0开始linux
博主ID:代码小豪

文章目录

    • 线程创建
      • 线程标识符
      • 线程参数
      • 多线程竞争资源
    • 回收线程
      • detach
    • 线程退出
      • pthread_cancel

线程创建

线程创建的函数为pthread_create。该函数是包含在posix线程库当中,posix线程是C语言处理线程的一个标准接口,我们的进程创建、杀死和回收线程,都可以通过posix库来完成完成,这些函数包含在<pthread.h>库函数当中,且大部分函数的名字都是以pthread开头,但是要注意该库不是C语言标准库,因此在使用<pthread.h>时,要记得gcc/g++的编译选项当中加上-lpthread

pthread_create函数原型如下:

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);

在我们上一篇文章当中就使用了pthread_create函数,但是博主当时并没有介绍完全这些参数,接下来博主会使用三个pthread_create的例子,让大家了解这些参数到底有什么用。

  • thread:输出型参数,创建一个pthread_t类型的变量,并将其地址传入函数当中,可以获得创建的线程的标识符
  • attr:设置线程的属性,使用NULL表示线程设置成默认模式,博主在本篇的例子中创建的都是默认模式的线程
  • start_routine:创建的线程的入口函数,类似于线程自己的main函数
  • arg:传入给新线程的参数

线程标识符

在我们上一篇文章中,我们提到linux将线程描述成一个轻量级进程(LWP),而且通过ps -aL可以查到轻量级进程的LWP号,那么LWP号和线程标识符thread有什么关系呢?

我们话不多说,直接上例子。

void* routine1(void* arg)//新线程入口函数
{while(true){::sleep(1);}
}int main()
{pthread_t tid1;//线程标识符pthread_create(&tid1,nullptr,routine1,nullptr);//创建新线程std::cout<<"thread1 tid:"<<tid1<<std::endl;while(true){sleep(1);}return 0;
}

接下来我们运行程序,打开另外一个终端,输入指令:ps -aL | head -1;ps -aL | grep thread

在这里插入图片描述
在这里插入图片描述
这很明显了,线程标识符和lwd号根本不是一个东西,但是它们指向的都是同一个线程,那么为什么要这样呢?首先我们搞清楚一个点,那就是<pthread.h>库是C语言封装的库,不是操作系统的系统调用库,因此C语言不必与操作系统在线程描述方面统一起来,因此lwp号是操作系统用于辨识轻量级进程的,而tid是C语言封装用来辨识线程的,虽然在linux当中lwp和线程是同一个东西。但是不妨碍C语言将其视为其他属性。

线程参数

相信大家对pthread_create的参数有点疑惑吧?第一个就是为什么我们写的start_routine(线程的入口地址)是要返回值为void*,参数为void的回调函数?返回值为void就算了,那个void的参数到底有什么用啊,我们平时创建出线程之后,线程自己就跳转到回调函数当中去了,那里轮得到我们自己使用。那么那个void的参数是什么,怎么传,别急,听我娓娓道来。

在pthread_create当中存在一个void的参数也很存疑。即void *arg,这个arg能传一个void类型的指针,这个指针其实就是给回调函数start_routine的参数,由于它是一个void*的指针,因此我们可以用它指向任何数据,整形、浮点型、任何的c/c++的内置类型,甚至可以是结构体,类的对象。

我们简简单单的定义一个类:

class thread
{
public:thread(std::string name,int a,int b):_name(name),_a(a),_b(b){;}void Excute(){std::cout<<_name<<'-'<<_a<<'-'<<_b<<std::endl;}private:std::string _name;int _a;int _b;
};

接下来我们在main函数当中创建指向该类的对象的指针,并且将该指针转为void*类型。作为参数传递给pthread_create。

int main()
{pthread_t tid;thread* objptr=new thread("thread-1",11,26);pthread_create(&tid,nullptr,routine1,(void*)objptr);while(true){sleep(1);}return 0;
}

而我们的routine1函数的参数不是要求是void类型的吗?实际上该参数就是我们传入的objptr,在routine1函数当中,我们可以将void的指针转换成对象类型的指针thread*。这样我们就可以在线程执行的函数当中,传入数据了。

void* routine1(void*arg)
{thread* obj=static_cast<thread*>(arg);//将void*类型转换成thread*obj->Excute();return nullptr;
}

接下来我们编译并执行该程序。
在这里插入图片描述
可以发现,线程入口函数的参数,其实就是我们传入给pthread_create的void*参数arg。

多线程竞争资源

线程之间的数据和代码是共享的,这意味着我们在运行多线程的进程时,会很难控制它们的运行情况。我们可以创建多个线程,让他们共同对一个全局变量进行修改,并且使用同一个函数进行打印,看看会发生什么。

int shared_arg=100;//共同使用的全局变量
void* sharedroutine(void* arg)//共同使用的函数
{std::string name(static_cast<char*>(arg));while(true){shared_arg++;std::cout<<"tid:"<<name<<"   arg:"<<shared_arg<<std::endl;::usleep(10);}
}int main()
{pthread_t tid1;//线程1标识符pthread_t tid2;//线程1标识符pthread_t tid3;//线程1标识符pthread_t tid4;//线程1标识符pthread_create(&tid1,nullptr,sharedroutine,(void*)"thread-1");//创建新线程1pthread_create(&tid2,nullptr,sharedroutine,(void*)"thread-2");//创建新线程2pthread_create(&tid3,nullptr,sharedroutine,(void*)"thread-3");//创建新线程3pthread_create(&tid4,nullptr,sharedroutine,(void*)"thread-4");//创建新线程4swhile(true){sleep(1);}return 0;
}

我们编译并执行程序。
在这里插入图片描述
可以发现,定义在全局当中变量shared_arg在所有的线程当中是共享的,线程1对其修改后,线程2、线程3、线程4的shared_arg也会跟着修改。那么此时有人就问了,局部变量就不共享吗?实际上也是共享的,只是局部变量会存在于栈区间上,而线程之间的栈区间是独立的,除非你能让线程找到其他线程栈区间上的变量。但是博主想不到该怎么做(haha)。

而且我们发现线程之间既然发生了写入重复的错误,那么这是如何导致的呢?我们了解过,线程会共享进程中的资源,其中就包括文件资源,而linux当中一切皆文件,包括显示器,因此如果我们向显示器写入数据,如果线程1和线程2同时都在向显示器写入数据,都会发现这种写入重复的情况。实际上不仅仅是显示器,只要是多个线程向任何一种文件写入数据,都有可能发生这种情况。

那么我们可以看到,线程对于公开资源的使用其实是需要我们控制的,因为你也不想发现程序执行完后,明明逻辑写的对的,但是一打开文件、发现写的数据都是乱七八糟的吧?而线程的控制方法,就是线程的互斥和同步,这一点我们后面再说。

回收线程

由于线程有其独立的内核数据结构,而内核数据结构是实打实存在于内存当中的,因此如果当线程结束后,没有对线程进行回收,这个内核数据结构就会一直存在于内存当中,造成内存泄漏,这个道理和进程回收很像。

那么为什么线程不会自动回收呢?这是因为我们的线程在结束之后是会有返回值的,这个返回值可以被用户所使用,因此操作系统不敢自动回收线程,因为操作系统也不确定我们用户到底用不用这个返回值,也不确定我们何时用线程的返回值。因此操作系统就只好一直帮助我们保存。直到用户主动回收为止。

那么线程回收的函数是什么?

int pthread_join(pthread_t thread, void **retval);
  • thread:pthread_t类型的参数,即我们想要回收的线程的线程描述符
  • retval:输出型参数,还记的我们线程的入口函数,其返回值是void*的吧?这个retval就是接收线程的返回值的。

如果pthread_join正常回收,其返回值为0,若pthread_join回收异常,则返回值为非0。但是博主在linux环境下没有找到引起pthread_join回收失败返回值为非0的情况。因为大部分时候如果线程出现了错误,进程就直接被杀死了。那么博主就不试了。

要注意,pthread_join会引起进程阻塞,而且线程不能自己回收自己,否则会造成deadlock(死锁),因为线程回收自己,会导致阻塞,而线程自己阻塞了,就永远无法结束,也就无法回收了,不能回收又会一直阻塞……(俄罗斯套娃)

关于回收,我们先简单认识这个函数,线程到底如何回收会更好?这一点我们后面再说。

话不多说,直接上例子。

void* routine1(void*arg)
{thread* obj=static_cast<thread*>(arg);//将void*类型转换成thread*obj->Excute();return (void*)10;
}

我们接着用上面使用过的代码,但是将其改造了一下,routine1的返回值从nulllptr变成了arg。

int main()
{pthread_t tid;thread* objptr=new thread("thread-1",11,26);pthread_create(&tid,nullptr,routine1,(void*)objptr);void* threadret=nullptr;int n=pthread_join(tid,&threadret);if(n==0) std::cout<<"回收tid:"<<tid<<"成功"<<std::endl;unsigned long ret=(unsigned long)threadret;std::cout<<ret<<std::endl;return 0;
}

在主线程当中,我们用void**类型的参数接收routine1函数的返回值,并且将其转换成unsigned long类型的变量。由于我们将其以void*类型返回了,因此要转换成unsigned long之后,才能看到返回值10。

接下来我们编译并运行。
在这里插入图片描述

可以发现确实能将线程回收,而且routine1当中的返回值确实是能通过pthread_join获得。

通常情况下,回收线程的工作都是交给主线程来完成,如果主线程结束,那么其他线就会继续运行,因此大部分情况下,主线程一定会比其他线程晚退出。

detach

由于主线程在回收线程时,需要阻塞等待待回收的线程结束,那么如果线程直接没有结束,那么主线程就会一直等待,这可能不是你想要的代码逻辑,那么有没有办法让主线程等待线程时,不阻塞等待。

线程有两种状态,其中一种是joined,也是我们创建新线程的默认状态,还有一种叫做detach。我们可以使用函数pthread_detach使线程进入detach状态,当线程处于detach状态下,对于该线程的回收操作将会失效。

int pthread_detach(pthread_t thread);

这个函数就不展示用例,我们向pthread_detach函数,传入线程标识符thread,thread就会进入detach状态。处于detach状态的线程,会在线程退出后,自动被操作系统回收。如果我们尝试用pthread_join回收detach状态下的线程,那么pthread_join只会返回一个非0的值,说明回收线程的操作失败了。detach的线程是不会被其他线程回收的。

线程退出

线程的退出方法有两种,一种是直接在线程的执行函数当中return,这个方法我们一直在前面的例子当中使用,因此不多bb。

第二种方法是在线程的执行函数使用pthread_exit函数。该函数原型如下:

void pthread_exit(void *retval);
  • retval:线程结束的返回值,在主线程当中可以使用pthread_joined接收到该返回值。

我们可以在线程的任意一个执行位置使用pthread_exit。当线程执行到该位置时,就会直接退出,这是和return结束线程不一样的地方,pthread_exit可以在任意的位置退出,即使线程处于调用中的函数。

void thread_to_do()
{std::cout<<"线程正在执行thread_todo"<<std::endl;//如果真推出了,显示器打印的信息只有这个pthread_exit((void*)10);
}void* routine1(void*arg)
{thread_to_do();std::cout<<"线程从thread_todo执行回来"<<std::endl;//如果没有退出,那么还会打印这个信息return (void*)10;
}

我们让线程在执行thread_to_do函数,接着在thread_to_do函数当中调用pthread_exit函数,如果真如我们所言,pthread_t能让线程无论在执行任何函数时,都能无视函数栈帧直接退出,那么屏幕上只会打印出“线程正在执行……”。而不会打印后面的信息。
在这里插入图片描述

那么有人可能会这么觉得,我们使用exit()函数是不是也能让线程退出呢?这句话对,但也不对,对是因为当线程执行到exit时,确实会退出,但是不对的地方在于,不仅仅执行exit()函数的线程会退出,进程中所有的一切线程,也会随之退出。因此exit其实是不能作为线程退出来使用的,因为它本身的作用是让进程退出,而非线程。因此在程序当中使用exit函数时,一定要注意你退出的要是进程还是线程。

pthread_cancel

严格来说,pthread_cancel函数并不属于线程退出,而是将一个特定的线程直接删除,被删除的线程需要被回收,一般这个工作都是让主线程来完成。我们先来看看pthread_cancel的函数原型。

int pthread_cancel(pthread_t thread);
  • thread:这是一个pthread_t类型的参数,即线程标识符,删除thread对应线程标识符的线程。

这个功能很简单,但是我们有一个问题是要解决的,那就是被删除的线程不是要回收吗?那么回收不就是能接收到线程的返回值,那么它的返回值是多少呢?

void* routine1(void*arg)
{thread* obj=static_cast<thread*>(arg);//将void*类型转换成thread*while(true){obj->Excute();sleep(1);}return (void*)10;
}int main()
{pthread_t tid;thread* objptr=new thread("thread-1",11,26);pthread_create(&tid,nullptr,routine1,(void*)objptr);sleep(1);pthread_cancel(tid);//将tid对应的线程删除sleep(5);void* threadret=nullptr;int n=pthread_join(tid,&threadret);if(n==0) std::cout<<"回收tid:"<<tid<<"成功"<<std::endl;long ret=(long)threadret;std::cout<<ret<<std::endl;return 0;
}

运行结果为:
在这里插入图片描述
pthread_cancel结束的进程,其返回值为PTHREAD_CANCELED;这是一个宏,我们可以找到这个宏定义。
在这里插入图片描述
也就是说,只要被pthread_cancel结束的线程,其返回值只会是-1。

相关文章:

从0开始linux(39)——线程(2)线程控制

欢迎来到博主的专栏&#xff1a;从0开始linux 博主ID&#xff1a;代码小豪 文章目录 线程创建线程标识符线程参数多线程竞争资源 回收线程detach 线程退出pthread_cancel 线程创建 线程创建的函数为pthread_create。该函数是包含在posix线程库当中&#xff0c;posix线程是C语言…...

对载入的3dtiles进行旋转、平移和缩放变换。

使用 params: {tx: 129.75845, //模型中心X轴坐标&#xff08;经度&#xff0c;单位&#xff1a;十进制度&#xff09;//小左ty: 46.6839, //模型中心Y轴坐标&#xff08;纬度&#xff0c;单位&#xff1a;十进制度&#xff09;//小下tz: 28, //模型中心Z轴坐标&#xff08;高…...

YOLO模型训练后的best.pt和last.pt区别

在选择YOLO模型训练后的权重文件best.pt和last.pt时&#xff0c;主要取决于具体的应用场景‌&#xff1a;‌12 ‌best.pt‌&#xff1a;这个文件保存的是在训练过程中表现最好的模型权重。通常用于推理和部署阶段&#xff0c;因为它包含了在验证集上表现最好的模型权重&#x…...

Qt 项目中同时使用 CMAKE_AUTOUIC 和 UiTools 的注意事项

在 Qt 项目开发中&#xff0c;.ui 文件是界面设计的重要组成部分。开发者可以通过两种主要方式使用 .ui 文件&#xff1a; 编译期处理&#xff1a;通过 Qt 的 uic 工具将 .ui 文件转化为 C 代码&#xff08;ui_xxx.h&#xff09;&#xff0c;静态绑定到项目中。运行时动态加载…...

不玩PS抠图了,改玩Python抠图

网上找了两个苏轼的印章图片&#xff1a; 把这两个印章抠出来的话&#xff0c;对于不少PS高手来说是相当容易&#xff0c;但是要去掉其中的水印&#xff0c;可能要用仿制图章慢慢描绘&#xff0c;图章的边缘也要慢慢勾画或者用通道抠图之类来处理&#xff0c;而且印章的红色也不…...

ubuntu 22.04 mini 安装,在配置网络时重启后配置文件被重置原因与解决方法

在 /etc/netplan/50-cloud-init.yaml 配置文件中有一段注释中有说明 rootlocalhost:/etc/netplan# cat 50-cloud-init.yaml # This file is generated from information provided by the datasource. Changes # to it will not persist across an instance reboot. To disab…...

【Go底层】time包Ticker定时器原理

目录 1、背景2、go版本3、源码解释【1】Ticker结构【2】NewTicker函数解释 4、代码示例5、总结 1、背景 说到定时器我们一般想到的库是cron&#xff0c;但是对于一些简单的定时任务场景&#xff0c;标准库time包下提供的定时器就足够我们使用&#xff0c;本篇文章我们就来研究…...

mac下Gpt Chrome升级成GptBrowser书签和保存的密码恢复

cd /Users/自己的用户名/Library/Application\ Support/ 目录下有 GPT\ Chrome/ Google/ GptBrowser/ GPT\ Chrome 为原来的chrome浏览器的文件存储目录. GptBrowser 为升级后chrome浏览器存储目录 书签所在的文件 Bookmarks 登录账号Login 相关的文件 拷贝到GptBrow…...

[Redis#6] list | 命令 | 应用 | 消息队列 | 微博 Timeline

目录 List 列表 特点 2. 命令 头插和尾插 下标 range 查询 头删和尾删 LINSERT LLEN LREM LTRIM LSET 阻塞命令 BLPOP BRPOP 操作 总结 3. 内部编码 ziplist&#xff08;压缩列表&#xff09; linkedlist&#xff08;链表&#xff09; ✔️quicklist(快速链…...

服务器数据恢复—raid6阵列硬盘被误重组为raid5阵列的数据恢复案例

服务器存储数据恢复环境&#xff1a; 存储中有一组由12块硬盘组建的RAID6阵列&#xff0c;上层linux操作系统EXT3文件系统&#xff0c;该存储划分3个LUN。 服务器存储故障&分析&#xff1a; 存储中RAID6阵列不可用。为了抢救数据&#xff0c;运维人员使用原始RAID中的部分…...

Xcode15(iOS17.4)打包的项目在 iOS12 系统上启动崩溃

0x00 启动崩溃 崩溃日志&#xff0c;只有 2 行&#xff0c;看不出啥来。 0x01 默认配置 由于我开发时&#xff0c;使用的 Xcode 14.1&#xff0c;打包在另外一台电脑 Xcode 15.3 Xcode 14.1 Build Settings -> Asset Catalog Compliter - Options Xcode 15.3 Build S…...

Netty的心跳机制怎么实现的?

大家好&#xff0c;我是锋哥。今天分享关于【Netty的心跳机制怎么实现的&#xff1f;】面试题。希望对大家有帮助&#xff1b; Netty的心跳机制怎么实现的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Netty 的心跳机制用于维持客户端和服务器之间的…...

常用函数的使用错题汇总

目录 new/delete malloc/free1. 语言和类型2. 内存分配3. 内存释放4. 安全性和类型安全5. 其他特性总结 线程停止文件流 new/delete malloc/free malloc/free 和 new/delete 是 C/C 中用于动态内存管理的两种方式&#xff0c;它们有一些重要的区别。以下是这两种方式的比较&…...

使用 `aircrack-ng`扫描、获取握手包

使用 aircrack-ng 工具集来扫描 5GHz WiFi 网络的过程与扫描 2.4GHz 网络类似&#xff0c;但需要注意一些特定的配置和命令。以下是一个详细的步骤指南&#xff0c;帮助你在 5GHz 频段上扫描 WiFi 网络并捕获握手包。 ### 前提条件 1. **操作系统**&#xff1a;通常在 Linux 系…...

css—轮播图实现

一、背景 最近和朋友在一起讨论的时候&#xff0c;我们提出了这样的一个提问&#xff0c;难道轮播图的效果只能通过js来实现吗&#xff1f;经过我们的一系列的争论&#xff0c;发现了这是可以通过纯css来实现这一效果的&#xff0c;CSS轮播图也是一种常见的网页展示方式&#x…...

Ardusub源码剖析(1)——AP_Arming_Sub

代码 AP_Arming_Sub.h #pragma once#include <AP_Arming/AP_Arming.h>class AP_Arming_Sub : public AP_Arming { public:AP_Arming_Sub() : AP_Arming() { }/* Do not allow copies */CLASS_NO_COPY(AP_Arming_Sub);bool rc_calibration_checks(bool display_failure)…...

ESP32-S3模组上跑通ES8388(10)

接前一篇文章&#xff1a;ESP32-S3模组上跑通ES8388&#xff08;9&#xff09; 二、利用ESP-ADF操作ES8388 2. 详细解析 上一回解析了es8388_init函数中的第3段代码&#xff08;也是实际与ES8388寄存器打交道的第1段代码&#xff09;&#xff0c;本回继续往下解析。为了便于理…...

AI/ML 基础知识与常用术语全解析

目录 一.引言 二.AI/ML 基础知识 1.人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09; (1).定义 (2).发展历程 (3).应用领域 2.机器学习&#xff08;Machine Learning&#xff0c;ML&#xff09; (1).定义 (2).学习方式 ①.监督学习 ②.无监督…...

【C#设计模式(15)——命令模式(Command Pattern)】

前言 命令模式的关键通过将请求封装成一个对象&#xff0c;使命令的发送者和接收者解耦。这种方式能更方便地添加新的命令&#xff0c;如执行命令的排队、延迟、撤销和重做等操作。 代码 #region 基础的命令模式 //命令&#xff08;抽象类&#xff09; public abstract class …...

Could not resolve com.android.tools.build:gradle:7.4.2.

Android Studio编译项目报错如下&#xff0c;始终无法下载解析7.4.2的gradle classpath A problem occurred configuring root project aistudyclient_questionlib. > Could not resolve all files for configuration :classpath.> Could not resolve com.android.tools…...

uniapp在App端定义全局弹窗,当打开关闭弹窗会触发onShow、onHide生命周期怎么解决?

在uniapp(App端)中实现自定义弹框&#xff0c;可以通过创建一个透明页面来实现。点击进入当前页面时&#xff0c;页面背景会变透明&#xff0c;用户可以根据自己的需求进行自定义&#xff0c;最终效果类似于弹框。 遇到问题&#xff1a;当打开弹窗(进入弹窗页面)就会触发当前页…...

2024 ccpc 辽宁省赛 E(构造 思维?)L(二分+一点点数论知识?)

E 题意&#xff1a; 可以注意到&#xff1a; 我的两种方格都四个方格的大小。 所以 如果存在一种摆放方式 那么 4|nm。 再考虑一种特殊的情况 22 &#xff0c;此时虽然我的积是4 但是无法摆放的。 1>对于 4 | n,或者 4 | m.我直接摆放第二种方格就可以了。 如果我n 是4 的…...

IIC 随机写+多次写 可以控制写几次

verilog module icc_tx#(parameter SIZE 2 , //用来控制写多少次 比如地址是0000 一个地址只能存放8bit数据 超出指针就会到下一个地址0001parameter CLK_DIV 50_000_000 ,parameter SPEED 100_000 ,parameter LED 50 )( input wire c…...

基于SpringBoot+Vue的汽车票网上预订系统-无偿分享 (附源码+LW+调试)

目录 1. 项目技术 2. 功能菜单 3. 部分功能截图 4. 研究背景 5. 研究目的 6. 可行性分析 6.1 技术可行性 6.2 经济可行性 6.3 操作可行性 7. 系统设计 7.1 概述 7.2 系统流程和逻辑 7.3 系统结构 8. 数据库设计 8.1 数据库ER图 &#xff08;1&#xff09;公告信…...

net9 abp vnext 多语言通过数据库动态管理

通过数据库加载实现动态管理&#xff0c;用户可以自己修改界面显示的文本&#xff0c;满足国际化需求 如图所示,前端使用tdesign vnext 新建表TSYS_Localization与TSYS_LocalizationDetail 国旗图标下载网址flag-icons: Free Country Flags in SVG 在Shared下创建下图3个文件 …...

pip安装github上的开源软件包

1、若本机中安装的有git&#xff0c;可使用githttps方式安装 # 以安装pyfolio软件包为例,安装指令如下 pip install githttps://github.com/quantopian/pyfolio.git 2、若本机中没有安装git&#xff0c;可以直接使用软件包的zip地址进行安装 # 以安装pyfolio软件包为例,安装…...

【LeetCode刷题之路】120:三角形最小路径和的两种解法(动态规划优化)

LeetCode刷题记录 &#x1f310; 我的博客主页&#xff1a;iiiiiankor&#x1f3af; 如果你觉得我的内容对你有帮助&#xff0c;不妨点个赞&#x1f44d;、留个评论✍&#xff0c;或者收藏⭐&#xff0c;让我们一起进步&#xff01;&#x1f4dd; 专栏系列&#xff1a;LeetCode…...

架构04-透明多级分流系统

零、文章目录 架构04-透明多级分流系统 1、透明多级分流系统 &#xff08;1&#xff09;概述 **定义&#xff1a;**透明多级分流系统是指在用户请求从客户端发出到最终查询或修改数据库信息的过程中&#xff0c;通过多个技术部件对流量进行合理分配&#xff0c;以提高系统的…...

云原生后端开发:构建现代化可扩展的服务

随着微服务架构的普及和容器化技术的成熟&#xff0c;云原生后端开发成为了构建现代化、可扩展系统的关键。本文将从云原生理念出发&#xff0c;结合实际案例&#xff0c;探讨如何使用 Kubernetes、服务网格、微服务架构等技术构建高效的云原生后端。 一、云原生的核心理念 1.…...

在Windows和Linux系统上获取网卡MAC地址及相关信息所有常用方法整理

摘要 在网络管理和故障排除中&#xff0c;了解如何获取网卡的MAC地址、IP地址以及网卡名称是系统管理员必备的技能。本文将介绍在Windows和Linux系统上手动获取网卡MAC地址的方法&#xff0c;并提供脚本以自动化获取服务器中网卡信息的过程。这些技巧和工具将帮助新手系统管理…...

制作苹果IOS.APP所使用步骤和方法-有步骤视情况待完善

1.获取开发工具 首先&#xff0c;您需要下载并安装Xcode。Xcode是苹果开发iOS和macOS应用程序的官方集成开发环境&#xff08;IDE&#xff09;。它包含了必要的工具&#xff0c;例如代码编辑器、调试器、编译器和界面构建器。Xcode可在Mac App Store中免费下载。 2.学习Swift或…...

【conda】全面解析 Conda 配置文件:从完整示例到最佳实践

目录 引言一、Conda 配置文件示例1.1 中英文注释示例1.2 文件编码格式 二、详细解释2.1 ssl_verify: true2.2 channels2.3 envs_dirs2.4 pkgs_dirs2.5 custom_channels2.6 remote_read_timeout_secs 和 remote_connect_timeout_secs2.7 show_channel_urls2.8 default_packages2…...

ffmpeg命令详解

原文网址&#xff1a;ffmpeg命令详解_IT利刃出鞘的博客-CSDN博客 简介 本文介绍ffmpeg命令的用法。 命令示例 1.mp4和avi的基本互转 ffmpeg -i D:\input.mp4 E:\output.avi ffmpeg -i D:\input.avi E:\output.mp4 -i 表示input&#xff0c;即输入。后面填一个输入地址和一…...

asyncio.run() 里面嵌套 asyncio.run() 可以吗?

[TOC](asyncio.run() 里面嵌套 asyncio.run() 可以吗&#xff1f;) 在 Python 的异步编程中&#xff0c;asyncio 是一个非常重要的模块&#xff0c;它提供了编写单线程并发代码的基础设施。asyncio.run() 是一个方便的函数&#xff0c;用于运行一个协程并管理事件循环的生命周…...

flutter in_app_purchase google支付 PG-GEMF-01错误

问题&#xff1a;PG-GEMF-01错误 flutter 使用in_app_purchase插件升降级订阅时报错PG-GEMF-01。 解决方案&#xff1a; 升降级订阅时&#xff0c;确保不调用 MethodCallHandlerImpl.java文件中的 setObfuscatedAccountId()方法、setObfuscatedProfileId()方法 原因&#xf…...

Flink 离线计算

文章目录 一、样例一&#xff1a;读 csv 文件生成 csv 文件二、样例二&#xff1a;读 starrocks 写 starrocks三、样例三&#xff1a;DataSet、Table Sql 处理后写入 StarRocks四、遇到的坑 <dependency><groupId>org.apache.flink</groupId><artifactId&…...

排序算法之插入排序篇

插入排序 思路&#xff1a; 就是将没有排序的元素逐步地插入到已经排好序的元素后面&#xff0c;保持元素的有序 视频的实现过程如下&#xff1a; 插入排序全过程 代码实现过程如下&#xff1a; public static void Insertion(int[] arr) { for (int i 1; i < arr.length…...

(11)(2.2) BLHeli32 and BLHeli_S ESCs(二)

文章目录 前言 1 传递支持 前言 BLHeli 固件和配置应用程序的开发是为了允许配置 ESC 并提供额外功能。带有此固件的 ESC 允许配置定时、电机方向、LED、电机驱动频率等。在尝试使用 BLHeli 之前&#xff0c;请按照 DShot 设置说明进行操作(DShot setup instructions)。 1 传…...

Unity之一键创建自定义Package包

内容将会持续更新&#xff0c;有错误的地方欢迎指正&#xff0c;谢谢! Unity之一键创建自定义Package包 TechX 坚持将创新的科技带给世界&#xff01; 拥有更好的学习体验 —— 不断努力&#xff0c;不断进步&#xff0c;不断探索 TechX —— 心探索、心进取&#xff01; …...

【AI】JetsonNano启动时报错:soctherm OC ALARM

1、问题描述 将JetsonNano烧写SD卡镜像为Ubuntu20.04后&#xff0c;启动时报错&#xff1a;soctherm OC ALARM&#xff0c;启动失败&#xff1b;然后系统一直重启 2、原因分析 “soctherm OC ALARM”是检测到系统温度超过安全阈值时发出的过热警告。 “soctherm”代表系统…...

道路机器人识别交通灯,马路,左右转,黄线,人行道,机器人等路面导航标志识别-使用YOLO标记

数据集分割 train组66% 268图片 validation集22% 91图片 test集12&#xff05; 48图片 预处理 没有采用任何预处理步骤。 增强 未应用任何增强。 数据集图片&#xff1a; 交通灯 马路 右转 向右掉头 机器人识别 人行横道 黄线 直行或右转 数据集下载&#xff1a; 道路…...

电子应用设计方案-31:智能AI音响系统方案设计

智能 AI 音响系统方案设计 一、引言 智能 AI 音响作为一种新兴的智能家居设备&#xff0c;通过融合语音识别、自然语言处理、音频播放等技术&#xff0c;为用户提供便捷的语音交互服务和高品质的音乐体验。本方案旨在设计一款功能强大、性能稳定、用户体验良好的智能 AI 音响系…...

SQL优化与性能——数据库设计优化

数据库设计优化是提高数据库性能、确保数据一致性和支持业务增长的关键环节。无论是大型企业应用还是小型项目&#xff0c;合理的数据库设计都能够显著提升系统性能、减少冗余数据、优化查询响应时间&#xff0c;并降低维护成本。本章将深入探讨数据库设计中的几个关键技术要点…...

脑网络组织与心跳动力学之间的耦合测量

摘要 近年来&#xff0c;人们对脑心相互作用的研究兴趣日益浓厚。许多研究提出了新的方法来探究大脑与心脏如何通信&#xff0c;从而对一些神经功能有了新的认识。然而&#xff0c;大多数框架只关注单个脑区域与心跳动态之间的相互作用&#xff0c;忽略了大脑的功能网络会随着…...

图像显示的是矩阵的行和列,修改为坐标范围。

x 3; y 3; f1x x^2 y^2; guance1 f1x; F (x, y) sqrt((x.^2 y.^2 - guance1).^2); % 使用点乘 [x, y] meshgrid(0:1:5, 0:1:5); Z F(x, y); figure; imagesc(Z); % 由于 imagesc 使用矩阵索引作为坐标&#xff0c;我们需要手动添加刻度 % 这里我们假设 x 和 y 的范围…...

一体化数据安全平台uDSP 入选【年度创新安全产品 TOP10】榜单

近日&#xff0c;由 FreeBuf 主办的 FCIS 2024 网络安全创新大会在上海隆重举行。大会现场揭晓了第十届 WitAwards 中国网络安全行业年度评选获奖名单&#xff0c;该评选自 2015 年举办以来一直饱受赞誉&#xff0c;备受关注&#xff0c;评选旨在以最专业的角度和最公正的态度&…...

[免费]SpringBoot+Vue景区订票(购票)系统【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的SpringBootVue大景区订票(购票)系统&#xff0c;分享下哈。 项目视频演示 【免费】SpringBootVue景区订票(购票)系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 现代经济快节奏发展以及不断完善升级的信息…...

力扣215:数组中第K大的元素

给定整数数组 nums 和整数 k&#xff0c;请返回数组中第 k 个最大的元素。 请注意&#xff0c;你需要找的是数组排序后的第 k 个最大的元素&#xff0c;而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 1: 输入: [3,2,1,5,6,4],k 2 …...

永久停用PostgreSQL 归档功能

文章目录 引言永久停用归档功能归档的优势归档的劣势开启归档的情况关闭归档的情况see also引言 PostgreSQL 是一个开源的关系型数据库系统,支持数据归档(WAL),可以实现数据备份、恢复和灾难恢复等功能。在使用 PostgreSQL 的过程中,如果 PostgreSQL 数据库开启了归档(a…...

23种设计模式-原型(Prototype)设计模式

文章目录 一.什么是原型设计模式&#xff1f;二.原型模式的特点三.原型模式的结构四.原型模式的优缺点五.原型模式的 C 实现六.原型模式的 Java 实现七. 代码解析八.总结 类图&#xff1a; 原型设计模式类图 一.什么是原型设计模式&#xff1f; 原型模式&#xff08;Prototype…...