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

2-6-1-1 QNX编程入门之进程和线程(四)

阅读前言

本文以QNX系统官方的文档英文原版资料“Getting Started with QNX Neutrino: A Guide for Realtime Programmers”为参考,翻译和逐句校对后,对在QNX操作系统下进行应用程序开发及进行资源管理器编写开发等方面,进行了深度整理,旨在帮助想要了解QNX的读者及开发者可以快速阅读,而不必查看晦涩难懂的英文原文,这些文章将会作为一个或多个系列进行发布,从遵从原文的翻译,到针对某些重要概念的穿插引入,以及再到各个重要专题的梳理,大致分为这三个层次部分,分不同的文章进行发布,依据这样的原则进行组织,读者可以更好的查找和理解。


1. 进程和线程

1.3. 线程和进程

2-6-1-1 QNX编程入门之进程和线程(一)

2-6-1-1 QNX编程入门之进程和线程(二)

2-6-1-1 QNX编程入门之进程和线程(三)

接前面章节内容继续。

1.3.3. 启动一个线程

既然我们已经了解了如何启动另一个进程,那么让我们来看看如何启动另一个线程。

任何线程都可以在同一进程中创建另一个线程,没有任何限制(当然,除了内存空间!)。最常见的方法是通过POSIX pthread_create() 调用:

#include <pthread.h>int
pthread_create (pthread_t *thread,const pthread_attr_t *attr,void *(*start_routine) (void *),void *arg);

pthread_create() 函数需要四个参数:

  • thread,指向存储线程 ID 的 pthread_t 的指针。
  • attr,属性结构。
  • start_routine,线程开始的例程。
  • arg,传递给线程的 start_routine 例程的参数。

请注意, 线程指针(thread)和属性结构体(attr )是可选的,你可以将它们传递为 NULL。
参数 thread 可用于存储新建线程的线程 ID。你会注意到,在下面的示例中,我们将传递一个 NULL,这意味着我们并不关心新创建线程的 ID 是什么。如果我们关心的话,可以这样做:

pthread_t tid;
pthread_create (&tid, …);
printf ("Newly created thread id is %d\n", tid);

这种用法其实很典型,因为你通常会想要知道哪个线程 ID 正在运行哪段代码。

这里有一个微妙的小问题。新创建的线程有可能在线程 ID(参数 tid 指针指向的内容)被填充之前就已开始运行,这意味着在将 tid 用作全局变量时一定要小心这一点。上面所显示的用法没有问题,因为 pthread_create() 调用已返回,这意味着 tid 值已正确填入。

新线程开始执行 start_routine(),参数为 arg。

1.3.3.1. 线程属性结构体

当你启动一个新线程时,它可以采用一些定义明确的默认值,或者你也可以显式地指定其特性。
在我们深入探讨线程属性函数之前,先来看看 pthread_attr_t 数据类型:

typedef struct {int                 __flags;size_t              __stacksize;void                *__stackaddr;void                (*__exitfunc)(void *status);int                 __policy;struct sched_param  __param;unsigned            __guardsize;
} pthread_attr_t;/* 
这些字段的基本使用方法如下: 
__flags
非数字(布尔)特性(例如,线程应 "可分离 detached" 运行还是 "可连接 joinable" 运行)。stacksize、 stackaddr 和 guardsize
堆栈的规格。__exitfunc
线程退出时执行的函数。__policy and __param
调度相关参数。
*/

以下是可供使用的函数:

属性管理相关:

  • pthread_attr_destroy()
  • pthread_attr_init()

标志(布尔特征)相关:

  • pthread_attr_getdetachstate()
  • pthread_attr_setdetachstate()
  • pthread_attr_getinheritsched()
  • pthread_attr_setinheritsched()
  • pthread_attr_getscope()
  • pthread_attr_setscope()
  • pthread_attr_getsuspendstate_np()
  • pthread_attr_setsuspendstate_np()

堆栈相关 :

  • pthread_attr_getguardsize()
  • pthread_attr_setguardsize()
  • pthread_attr_getstack()
  • pthread_attr_setstack()
  • pthread_attr_getstackaddr()
  • pthread_attr_setstackaddr()
  • pthread_attr_getstacklazy()
  • pthread_attr_setstacklazy()
  • pthread_attr_getstackprealloc()
  • pthread_attr_setstackprealloc()
  • pthread_attr_getstacksize()
  • pthread_attr_setstacksize()

调度相关:

  • pthread_attr_getschedparam()
  • pthread_attr_setschedparam()
  • pthread_attr_getschedpolicy()
  • pthread_attr_setschedpolicy()


这个列表看起来很长,但实际上我们只需要关心其中一半,因为它们是以 "get "和 "set" 的形式成对出现的(不过,pthread_attr_init()pthread_attr_destroy() 除外) 。

在研究属性相关函数之前,有一点需要注意。在使用属性结构体之前,必须调用 pthread_attr_init() 对其进行初始化, 然后使用相应的 pthread_attr_set*() 函数对其进行设置,最后再调用 pthread_create() 函数进行线程的创建。 在线程创建之后再更改属性结构体的内容是没有效果的。
 

1.3.3.1.1. 线程属性管理

在使用属性结构体之前,必须调用 pthread_attr_init() 函数对其进行初始化。

...
pthread_attr_t  attr;
...
pthread_attr_init (&attr);

你可以调用 pthread_attr_destroy() 函数来 “反初始化” 线程属性结构体,但几乎没人会这么做(除非你的代码要遵循 POSIX 标准)。

在接下来的描述中,我已用 “(default)” 标记出了默认值。

1.3.3.1.2. 线程属性“flags”

让我们从布尔型线程属性开始说起。

  • 要创建一个 “可连接(joinable)” 的线程(意思是另一个线程能够通过 pthread_join() 函数与该线程的“终止”进行同步),你可以像下面这样:
(default)
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE);

要创建一个无法被连接的线程(称为 "detached" 线程),可以使用下面的方法:

pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);

  • 如果希望线程继承创建者线程的调度属性(即具有相同的调度策略和优先级),你可以这样:
(default)
pthread_attr_setinheritsched (&attr, PTHREAD_INHERIT_SCHED);

要创建一个由属性结构体本身指定调度属性的线程(使用 pthread_attr_setschedparam()pthread_attr_setschedpolicy() 进行调度属性设置),可以使用下面的方法:

pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);

  • 在 QNX Neutrino 7.0.1 或更高版本中,如果你不希望线程在创建时就进入挂起状态(suspended state),可以像下面这样:
(default)
pthread_attr_setsuspendstate_np (&attr, PTHREAD_NOT_SUSPENDED);

如果你希望线程在创建时就处于挂起状态(suspended),你可以使用下面这个方式:

pthread_attr_setsuspendstate_np(&attr, PTHREAD_SUSPENDED);

  • 最后,你永远不会调用 pthread_attr_setscope()。为什么?因为 QNX Neutrino 只支持 "system" 作用域,这也是属性结构体初始化时的默认值。(“system”作用域意味着所有线程都在系统中互相竞争 CPU;而另一个值“process”则意味着线程在进程内相互竞争 CPU,而内核则对进程进行调度)。 如果你坚持要调用,只能按如下方式进行调用:
(default)
pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);

1.3.3.1.3. 线程属性“stack”

设置线程属性堆栈参数的函数如下:

int
pthread_attr_setstack (pthread_attr_t *attr, void *addr, size_t ssize );int
pthread_attr_setstackaddr (pthread_attr_t *attr, void *addr);int
pthread_attr_setguardsize (pthread_attr_t *attr, size_t gsize);int
pthread_attr_setstacklazy (pthread_attr_t *attr, int lazystack);int
pthread_attr_setstackprealloc (pthread_attr_t * attr, size_t psize);int
pthread_attr_setstacksize (pthread_attr_t *attr, size_t ssize);

这些函数都将属性结构作为它们的第一个参数;其他参数则从以下各项中选取:

addr栈的地址(如果由你提供栈地址的话)。

gsize“保护(guard)” 区域的大小。

lazystack指示栈是应该按需从物理内存中分配,还是预先分配。

psize要为线程的 MAP_LAZY 栈预分配的内存量。

ssize栈的大小。

保护区域(guard area)是紧挨着栈(stack)的一块内存区域,线程不能对其进行写入操作。如果线程对其进行了写入(意味着栈即将溢出),那么线程将会收到 SIGSEGV 信号。如果保护区域大小(guardsize)为 0,则表示不存在保护区域。这也意味着不会进行栈溢出检查。如果 guardsize 不为 0,那么它至少会被设置为系统范围内的默认保护区域大小(你可以通过调用 sysconf() 函数,并传入常量 _SC_PAGESIZE 来获取该默认大小)。需要注意的是,保护区域大小至少会和一个“页面”一样大(例如,在 x86 处理器上是 4KB)。另外,还要注意保护区域的“页面”并不会占用任何实际的物理内存,它只是通过虚拟地址(内存管理单元,即 MMU)的 “技巧” 来实现的。

addr 是栈的地址(如果你提供了的话)。你可以将其设置为 NULL,这意味着需要系统将为线程进行分配(并且会自动释放!)栈。指定栈的好处在于你可以事后对栈的深度进行分析。具体做法是分配一个栈区域,用一个“标识”(例如,反复重复的字符串“STACK”)填充它,然后让线程运行。当线程运行结束后,你查看栈区域,看看线程覆盖你的标识到了什么程度,这样就能得知在这次特定运行过程中所使用的栈的最大深度。

ssize 参数用于指定栈的大小。如果你通过 addr 提供了栈,那么 ssize 就应该是该数据区域的大小。如果你没有通过 addr 提供栈(也就是传递了 NULL),那么 ssize 参数会告知系统应该为你分配多大的栈。如果你将 ssize 指定为 0,系统会为你选择默认的栈大小。显然,将 ssize 指定为 0 同时又通过 addr 指定一个栈的地址,这种做法很不好。这样做,实际上相当于在说“这是一个指向某个对象的指针,而这个对象的大小是某个默认值”。 但是,问题在于你所指定的对象大小和传递的地址值之间没有关联。

如果通过 addr 提供了栈,那么对于该线程来说不存在自动的栈溢出保护机制(即不存在保护区域)。不过,你当然可以自己使用 mmap()mprotect() 函数来设置相关保护机制。

最后,lazystack 参数用于指示物理内存是应该按需分配(使用值 PTHREAD_STACK_LAZY)还是预先全部分配(使用值 PTHREAD_STACK_NOTLAZY)。按需分配栈(根据需要分配)的好处在于线程不会占用比实际所需更多的物理内存。预先全部分配方法的好处在于,在内存不足的环境中,线程在运行期间需要额外的栈空间但又没有剩余内存时,不会莫名其妙地终止运行。如果你使用后一种方法(即 PTHREAD_STACK_NOTLAZY),你很可能会想要设置栈的实际大小,而不是采用默认大小,因为默认大小通常是比较大的。

1.3.3.1.4. 线程属性“sheduling”

最后,如果你确实为 pthread_attr_setinheritsched() 函数指定了 PTHREAD_EXPLICIT_SCHED 参数,那么你就需要一种方法来指定即将创建的线程的调度策略以及优先级。

可以通过以下两个函数来实现:

int
pthread_attr_setschedparam (pthread_attr_t *attr,const struct sched_param *param);
int
pthread_attr_setschedpolicy (pthread_attr_t *attr,int policy);

调度策略很简单,它取值为 SCHED_FIFOSCHED_RRSCHED_OTHER 其中之一。

目前,SCHED_OTHER 也是被映射为 SCHED_RR

param 是一个结构体,这里与之相关的成员只有一个:sched_priority。通过直接赋值的方式将该值设置为期望的优先级即可。

需要留意的一个常见错误是指定了 PTHREAD_EXPLICIT_SCHED 参数后,却只设置了调度策略。问题在于,在一个已初始化的属性结构中,param.sched_priority 的值为 0。这个优先级与空闲进程的优先级相同,这意味着你新创建的线程将会与空闲进程竞争 CPU 资源。这种情况我亲身经历过,印象深刻呢。(偷笑)

已经有很多人被这个问题困扰过了,所以优先级 0 是预留给空闲线程的。你根本不能让一个线程以优先级 0 来运行。

1.3.3.2. 几个例子

让我们来看一些示例。我们假定已经包含了合适的头文件(<pthread.h><sched.h>),并且即将要创建的线程名为 new_thread(),它的函数原型声明和定义都是正确的。

创建线程最常见的方式就是简单地使用默认值:

pthread_create (NULL, NULL, new_thread, NULL);

在上述示例中,我们使用默认值创建了新线程,并给它传递了一个 NULL 作为其唯一的参数(也就是上面 pthread_create() 调用中的第三个 NULL)。

通常来说,你可以通过参数(arg 字段)给新线程传递任何你想要传递的内容。在这里我们传递数字 123

pthread_create (NULL, NULL, new_thread, (void *) 123);

下面是一个更复杂些的示例,创建一个不可结合的(non-joinable)线程,该线程采用轮转调度算法且优先级为 15

pthread_attr_t attr;// 初始化属性结构
pthread_attr_init (&attr);// 将分离状态设置为“分离”
pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);// 覆盖默认的继承调度属性设置
pthread_attr_setinheritsched (&attr, PTHREAD_EXPLICIT_SCHED);
pthread_attr_setschedpolicy (&attr, SCHED_RR);
attr.param.sched_priority = 15;// 最后,创建线程
pthread_create (NULL, &attr, new_thread, NULL);

要看看一个多线程程序 “是什么样子的”,你可以在 shell 中运行 pidin 命令。假设我们的程序名为 spud。如果我们在 spud 创建线程之前运行一次 pidin 命令,然后在 spud 又创建了两个线程之后(总共三个线程)再运行一次 pidin 命令,输出结果看起来会是这样的(我对 pidin 的输出进行了简化,只展示 spud 的相关内容):

# pidin
pid    tid name               prio STATE       Blocked
12301   1 spud                10r READY
# pidin
pid    tid name               prio STATE       Blocked
12301   1 spud                10r READY
12301   2 spud                10r READY
12301   3 spud                10r READY

如你所见,进程 spud(进程 ID 为 12301)有三个线程(在 “tid” 列下可以看到)。这三个线程以优先级 10 运行,采用轮转调度算法(由 10 后面的 “r” 表示)。这三个线程都处于 “READY” 状态,这意味着它们能够使用 CPU,但当前并没有在 CPU 上运行(当前有另一个优先级更高的线程正在运行)。

既然我们已经了解了创建线程的所有相关内容,现在让我们来看看如何以及在哪些地方会用到线程吧。

1.3.3.3. 在这里使用线程是个好主意

有两类问题比较适合运用线程来解决。

线程就好比是 C++ 中的运算符重载;在当时看来,用一些有意思的用法去重载每一个运算符似乎是个好主意,但这会让代码变得难以理解。线程方面也是类似的情况,你可以创建大量的线程,然而额外增加的复杂性会使你的代码难以理解,进而难以维护。另一方面,明智地使用线程,则会让代码在功能上显得非常简洁明了。

在能够并行化操作的情况下,线程的作用很大,能让人马上想到很多数学问题(比如图形处理、数字信号处理等等)。另外,当你希望一个程序在共享数据的同时执行多个独立功能时,线程也非常有用,例如一个同时为多个客户端提供服务的网络服务器就是如此。我们接下来会对这两类情况进行探讨。


未完待续,请继续关注本专栏内容……

相关文章:

2-6-1-1 QNX编程入门之进程和线程(四)

阅读前言 本文以QNX系统官方的文档英文原版资料“Getting Started with QNX Neutrino: A Guide for Realtime Programmers”为参考&#xff0c;翻译和逐句校对后&#xff0c;对在QNX操作系统下进行应用程序开发及进行资源管理器编写开发等方面&#xff0c;进行了深度整理&…...

Vue开发环境搭建上篇:安装NVM和NPM(cpnm、pnpm)

文章目录 引言I 安装NVM1.1 Windows系统安装NVM,实现Node.js多版本管理1.2 配置下载镜像1.3 NVM常用操作命令II NPM永久使用淘宝源安装 cnpm安装pnpm【推荐】see also: vscode常用插件引言 淘宝镜像:http://npm.taobao.org 和 http://registry.npm.taobao.org 已在 2022.06.3…...

2.微服务灰度发布落地实践(agent实现)

文章目录 前言java agent的介绍基础实现agent端 http服务实现agent端api接口 前言 据上一篇&#xff0c;设计方案的分析&#xff0c;综合考虑&#xff0c;最终决定,客户端采用agent方案实现&#xff0c;具本原因不再赘述&#xff0c; 感觉兴趣的小伙伴可以回头了解一下.该篇主…...

网络安全专业术语

网络安全专有名词详解 1.肉鸡 被黑客操控的终端设备&#xff08;电脑、服务器、移动设备等等&#xff09;&#xff0c;黑客可以随心所欲的操作这些终端设备而不会被发觉。 2.木马 表面上伪装成正常的程序&#xff0c;但是当这些程序运行时候就会获取整个系统的控制权限&#…...

SpringMVC核心、两种视图解析方法、过滤器拦截器 “ / “ 的意义

SpringMVC的执行流程 1. Spring MVC 的视图解析机制 Spring MVC 的核心职责之一是将数据绑定到视图并呈现给用户。它通过 视图解析器&#xff08;View Resolver&#xff09; 来将逻辑视图名称解析为具体的视图文件&#xff08;如 HTML、JSP&#xff09;。 核心流程 Controlle…...

ubuntu快速入门

1.进入某个文件夹 cd workspace/2.tab自动补全 3.列出当前文件夹所有文件 ls列出所有文件包括隐藏文件 ls -a 4.创建文件夹 mkdir linuxLearn 5.创建文件 gedit command.sh在commmand.sh键入 echo hello echo hi? echo how are you? PS:touch hello.txt(也可以创建新…...

HarmonyOS NEXT应用开发实战:一分钟写一个网络接口,JsonFormat插件推荐

在开发鸿蒙操作系统应用时&#xff0c;网络接口的实现往往是一个繁琐且重复的过程。为了提高开发效率&#xff0c;坚果派(nutpi.net)特别推出了一个非常实用的插件——JsonFormat。这款插件的主要功能是将JSON格式的数据直接转换为arkts的结构定义&#xff0c;让我们在编写接口…...

光谱相机与普通相机的区别

一、成像目的 普通相机&#xff1a;主要目的是记录物体的外观形态&#xff0c;生成人眼可见的、直观的二维图像&#xff0c;重点在于还原物体的形状、颜色和纹理等视觉特征&#xff0c;以供人们进行观赏、记录场景或人物等用途。例如&#xff0c;拍摄旅游风景照片、人物肖像等…...

贝叶斯神经网络(Bayesian Neural Network)

最近在研究贝叶斯神经网络,一些概念一直搞不清楚,这里整理一下相关内容,方便以后查阅。 贝叶斯神经网络(Bayesian Neural Network) 贝叶斯神经网络(Bayesian Neural Network)1. BNN 的核心思想2. BNN 的优化目标3. BNN 的结构与特点4. BNN 的训练过程5. BNN 的优缺点6. …...

使用FFmpeg进行拉流和推流操作

FFmpeg是一款强大的多媒体处理工具&#xff0c;可以用于视频的录制、转换、推流和拉流等操作。下面将详细介绍如何使用FFmpeg进行拉流和推流操作。 1. FFmpeg推流操作 推流是将本地的音视频流推送到流媒体服务器上&#xff0c;例如主播将本地电脑上的画面推流到直播平台的流媒…...

flutter插件开发-ios

flutter插件开发是一个重要的技能&#xff0c;拓展flutter与原生的通信&#xff0c;将一些公用的东西封装&#xff0c;给不同的项目使用。 阅读前置&#xff1a; flutter基本通道调用 objective-c基础语法 ios项目基础知识 目录 1、创建一个插件项目2、项目结构3、编写原生代码…...

【代码随想录|完全背包问题】

518.零钱兑换|| 题目链接&#xff1a;518. 零钱兑换 II - 力扣&#xff08;LeetCode&#xff09; 这里求的是组合数&#xff0c;就是不强调元素排列的顺序&#xff0c;211和121是同一个数那种&#xff0c;要先遍历物品&#xff0c;这样的话我算出来的每个值才是按顺序121&…...

xss csrf怎么预防?

一、XSS&#xff08;跨站脚本攻击&#xff09;预防 XSS 是指攻击者向目标网站注入恶意脚本&#xff0c;从而在用户浏览器中执行。 1. 输入过滤 清理用户输入&#xff1a; 拦截或清理HTML特殊字符&#xff08;如 <, >, , ", &&#xff09;。使用安全库&#x…...

黑神话悟空游戏鼠标光标使用教程与下载

效果图&#xff1a; 鼠标光标特点 这套鼠标光标的设计灵感来源于《黑神话&#xff1a;悟空》游戏中的角色和元素&#xff0c;具有以下特点&#xff1a; • 主题鲜明&#xff1a;光标设计紧扣游戏主题&#xff0c;采用了游戏中的元素&#xff0c;让玩家在使用电脑时也能感受到…...

<数据集>芝麻作物和杂草识别数据集<目标检测>

数据集下载链接 &#xff1c;数据集&#xff1e;芝麻作物和杂草识别数据集&#xff1c;目标检测&#xff1e;https://download.csdn.net/download/qq_53332949/90181548数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;1300张 标注数量(xml文件个数)&#xff1a;130…...

实测数据处理(CS算法处理:可斜视)——SAR成像算法系列(十一)

系列文章目录 《SAR学习笔记-SAR成像算法系列&#xff08;一&#xff09;》 《线性调频变标算法&#xff08;CSA&#xff09;-SAR成像算法系列&#xff08;四&#xff09;》 文章目录 前言 一、算法流程 1.1、回波信号生成 1.2、CS处理 1.3、距离脉压 1.4、方位脉压 1.5…...

【强化学习入门笔记】 2.4 时序差分算法

本系列为学习赵世钰老师的《强化学习的数学原理》所作的学习笔记. 本节我们将介绍强化学习中的蒙特卡洛方法. 2.4.1 Robbins-Monro算法 Robbins-Monro算法是一种随机近似方法&#xff0c;通过迭代的方式求解非线性方程。 假设我们要求解: g ( w ) 0 g(w)0 g(w)0, 但是我们…...

Scrapy数据解析+保存数据

Scrapy数据解析保存数据 目录 1.数据解析 2.基于item存放数据并提交给管道 3.用txt文件来保存数据 今天我们需要爬取B站数据并保存到txt文件里面。 我们先打开B站, 然后点击热门, 进去之后再点击排行榜: 我们打开F12后, 可以看到, 我们想要的请求, 轻而易举的就可以拿到(…...

Redis--缓存穿透、击穿、雪崩以及预热问题(面试高频问题!)

缓存穿透、击穿、雪崩以及预热问题 如何解决缓存穿透&#xff1f;方案一&#xff1a;缓存空对象方案二&#xff1a;布隆过滤器什么是布隆过滤器&#xff1f;优缺点 方案三&#xff1a;接口限流 如何解决缓存击穿问题&#xff1f;方案一&#xff1a;分布式锁方案一改进成双重判定…...

【Python高级353】python实现多线程版本的TCP服务器

前面学了了套接字编程、tcp服务端客户端开发、面向对象版的服务端客户端、带有端口复用的服务端。 这里使用多线程开发多任务版的服务端 多任务版本的TCP服务器 来一个客户&#xff0c;就为其创建一个线程 import socket import threadingclass WebServer:# 3、定义一个__ini…...

【Pandas】pandas Series to_period

Pandas2.2 Series Conversion 方法描述Series.astype用于将Series对象的数据类型转换为指定类型的方法Series.convert_dtypes用于将 Series 对象的数据类型智能地转换为最佳可能的数据类型的方法Series.infer_objects用于尝试推断 Series 中对象&#xff08;object&#xff0…...

深度学习领域车辆识别与跟踪

深度学习中车辆识别是一个广泛应用的领域&#xff0c;它涵盖了从车辆检测到车型识别的多个方面。以下是对深度学习中车辆识别与车辆相关内容的详细探讨&#xff1a; 一、车辆检测 车辆检测是车辆识别中的基础任务&#xff0c;其目标是在图像或视频中准确地定位出车辆的位置。…...

数学建模 绘图 图表 可视化(2)

文章目录 前言柱形图条形图克利夫兰点图系列坡度图南丁格尔玫瑰图径向柱图极坐标图词云图总结参考资料 前言 承接上期 数学建模 绘图 图表 可视化&#xff08;1&#xff09;的总体描述&#xff0c;这期我们继续跟随《Python 数据可视化之美 专业图表绘制指南》步伐来学习其中l…...

vue源码分析(十)—— 生命周期

文章目录 前言一、关键方法 callHook二、详细的钩子函数说明1.beforeCreate和create2.beforeMount & mounted注意点组件&#xff08;非根组件&#xff09;的渲染节点&#xff08;1&#xff09;invokeInsertHook函数&#xff08;2&#xff09;insert方法&#xff08;3&#…...

[创业之路-222]:波士顿矩阵与GE矩阵在业务组合选中作用、优缺点比较

目录 一、波士顿矩阵 1、基本原理 2、各象限产品的定义及战略对策 3、应用 4、优点与局限性 二、技术成熟度模型与产品生命周期模型的配对 1、技术成熟度模型 2、产品生命周期模型 3、技术成熟度模型与产品生命周期模型的配对 三、产品生命周期与产品类型的对应关系 …...

# 【超全面了解鸿蒙生命周期】-生命周期补充

【超全面了解鸿蒙生命周期】-生命周期补充 鸿蒙所有的生命周期函数梳理 文章目录 【超全面了解鸿蒙生命周期】-生命周期补充前言一、AbilityStage的生命周期二、ExtensionAbility卡片生命周期三、Web组件常用生命周期 前言 本文是继之前写的生命周期函数梳理的进一步补充&…...

sentinel-请求限流、线程隔离、本地回调、熔断

请求限流&#xff1a;控制QPS来达到限流的目的 线程隔离&#xff1a;控制线程数量来达到限流的目录 本地回调&#xff1a;当线程被限流、隔离、熔断之后、就不会发起远程调用、而是使用本地已经准备好的回调去提醒用户 熔断&#xff1a;熔断也叫断路器&#xff0c;当失败、或者…...

unplugin-vue-router 的基本使用

1. 前言 在Vue3开发过程中&#xff0c;每次创建新的页面都需要注册路由&#xff0c;需要在src/router.ts中新增页面的路径&#xff0c;并将URL路径映射到组件中&#xff0c;如下所示&#xff1a; import { createMemoryHistory, createRouter } from vue-routerimport HomePage…...

[Leetcode] 最大子数组和 [击败99%的解法]

解法1&#xff1a; 暴力解法 遍历每个元素&#xff0c;从它当前位置一直加到最后&#xff0c;然后用一个最大值来记录全局最大值。 代码如下&#xff1a; class Solution {public int maxSubArray(int[] nums) {long sum, max nums[len-1];for (int i0; i<nums.length;…...

SSRF服务端请求Gopher伪协议白盒测试

前言 是什么SSRF&#xff1f; 这个简单点说就是 服务端的请求伪造 就是这个如果是个 请求图片的网站 他的目的是请求外部其他网站的 图片 但是 SSRF指的是让他请求本地的图片 再展示出来 请求的是他的服务器上的图片 SSRF(Server-Side Request Forgery:服务器端请求伪造) …...

[2029].第6-06节:MyISAM引擎中的索引与 InnoDB引擎中的索引对比

所有博客大纲 后端学习大纲 MySQL学习大纲 1.MyISAM索引&#xff1a; 1.1.B树索引适用存储引擎&#xff1a; 1.B树索引适用存储引擎如下表所示&#xff1a; 2.即使多个存储引擎都支持同一种类型的B树索引&#xff0c;但它们的实现原理也是不同的 Innodb和MyISAM默认的索引是B…...

WOFOST作物模型(3):(本地化校准)优化PCSE模型中的参数

目录 一、准备自己的LAI观测数据二、优化参数三、损失函数四、NLOPT优化五、优化结果可视化一、准备自己的LAI观测数据 在进行田间实测后,得到自己的LAI观测数据 在程序这个地方输入自己的LAI采样日期和观测值 二、优化参数 这里主要选择了TDWI(Total Dry Weight at ger…...

如何修改pip全局缓存位置和全局安装包存放路径

使用场景&#xff1a; 在默认情况下&#xff0c;pip 会将安装的包存放在 Python 环境的 site-packages 目录下&#xff0c;会使用到系统盘的内存。 当遇到系统盘的内存很小的时候,需要修改pip的全局缓存位置和全局安装包存放路径,可以极大的节省系统盘内存 详细步骤&#xff…...

ZooKeeper注册中心实现

具体步骤 安装ZooKeeper&#xff08;启动端口占用&#xff0c;2181&#xff1a;客户端&#xff0c;8080&#xff1a;管理端&#xff09;引入客户端依赖实现注册中心接口SPI补充ZooKeeper注册中心 引入依赖 <!-- zookeeper --> <dependency><groupId>org.a…...

PyTorch快速入门教程【小土堆】之DataLoader的使用

视频地址DataLoader的使用_哔哩哔哩_bilibili dataset数据集&#xff0c;相当于一副扑克&#xff0c;dataloader数据加载器相当于我们的手&#xff0c;选择摸几张牌&#xff0c;怎么摸牌 import torchvision# 准备的测试数据集 from torch.utils.data import DataLoader from …...

khadas edge2安装ubuntu22.04与ubuntu20.04 docker镜像

khadas edge2安装ubuntu22.04与ubuntu20.04 docker镜像 一、资源准备1.1 镜像文件1.2 刷机工具1.3 ubuntu20.04 docker镜像&#xff08;具备demon无人机所需各种驱动&#xff09; 二、开始刷机&#xff08;安装ubuntu22.04系统&#xff09;2.1 进入刷机状态2.2 刷机 三、docker…...

大数据面试笔试宝典之Kafka面试

1.Kafka 如何实现高吞吐率 Kafka 如何实现高吞吐率? 参考答案: 1)顺序读写...

新手SEO入门指南如何有效提升网站排名

内容概要 在进行搜索引擎优化&#xff08;SEO&#xff09;时&#xff0c;了解基本概念与重要性是首要步骤。SEO不仅仅是提升网站在搜索引擎中排名的手段&#xff0c;它还关乎用户体验和网站内容的质量。随着互联网的发展&#xff0c;越来越多的人意识到优秀的SEO策略能带来持续…...

【Redis】:初识Redis

1.1 盛赞 Redis Redis 是⼀种基于键值对&#xff08;key-value&#xff09;的 NoSQL 数据库&#xff0c;与很多键值对数据库不同的是&#xff0c;Redis 中的值可以是由 string&#xff08;字符串&#xff09;、hash&#xff08;哈希&#xff09;、list&#xff08;列表&#xf…...

C-5 B样条曲线

C-5 B样条曲线 N i , 0 ( u ) { 1 , u i ≤ u < u i 1 0 , o t h e r s N_{i,0}(u)\left\{\begin{matrix} 1 , \quad u_i\le u <u_{i1} \\0 ,\quad others \qquad \quad\end{matrix}\right. Ni,0​(u){1,ui​≤u<ui1​0,others​ N i , p ( u ) u − u i u i p −…...

python安装

python安装 1.下载2.安装3.验证安装成功 1.下载 &#xff08;1&#xff09;下载网址&#xff1a;https://www.python.org/downloads/windows/ 进入后稍等一会&#xff0c;比较慢 &#xff08;2&#xff09;选择版本 2.安装 &#xff08;1&#xff09;双击或者以管理员身份运…...

游戏引擎学习第65天

回顾我们在模拟区域更改方面的进展 目前我们正在进行游戏的架构调整&#xff0c;目标是建立一个引擎架构。我们正在实施的一个关键变化是引入模拟区域的概念&#xff0c;这样我们可以创建非常大的游戏世界&#xff0c;而这些世界的跨度不必受限于单个浮点变量。 通过这种方式…...

代码随想录算法训练营第十六天-二叉树-513.找树左下角的值

左下角不是以为的左下角&#xff0c;而最后一层最左侧的节点也是就是说一个右叶子节点&#xff0c;也可能是最左下角&#xff0c;当然是在其左侧再无其它同级节点看视频讲解使用的递归与回溯方法&#xff0c;自己是完全想不到的&#xff0c;对这道题解法完全是脑袋空空 #inclu…...

力扣第122题:买卖股票的最佳时机 II

力扣第122题&#xff1a;买卖股票的最佳时机 II - C语言解法 题目描述 给定一个数组 prices&#xff0c;其中 prices[i] 是一支股票第 i 天的价格。你可以多次买入和卖出股票&#xff0c;求能够获得的最大利润。 注意&#xff1a; 你不能同时参与多笔交易&#xff08;即必须…...

【Spring MVC】第一站:Spring MVC介绍配置基本原理

目录 1.引入 2. Java web的发展史 Model I 和Model II 3. MVC模式 4. Spring MVC配置 5. SpringMVC原理 5.1 SpringMVC中心控制器 6. Maven配置 1.引入 $$ Spring与Spring MVC的区别 SSM 包含三部分&#xff1a; Spring MVCSpringMybatis SSM就是升级版的Servlet。 Servlet…...

密钥登录服务器

1. 生成 SSH 密钥对 如果您还没有生成密钥对&#xff0c;可以使用以下命令生成&#xff1a; ssh-keygen 在 root 用户的家目录中生成了一个 .ssh 的隐藏目录&#xff0c;内含两个密钥文件&#xff1a;id_rsa 为私钥&#xff0c;id_rsa.pub 为公钥。 在提示时&#xff0c;您可…...

Java中StopWatch的使用详解

stopWatch 是org.springframework.util 包下的一个工具类&#xff0c;使用它可直观的输出代码执行耗时&#xff0c;以及执行时间百分比。 在未使用这个工具类之前&#xff0c;如果我们需要统计某段代码的耗时&#xff0c;我们会这样写: public static void main(String[] args…...

安全运营 -- splunk restapi 最小权限

0x00 背景 最小化权限原则&#xff0c;为每个功能&#xff0c;每个账户分配最小的权限。 0x01 实践 只需要7个 capability: Youll need to add certain capabilities to that user or that userss role(s).[capability::rest_apps_management] * Lets a user edit settings …...

12. 日常算法

1. 主持人调度&#xff08;一&#xff09; 题目来源 class Solution { public:bool hostschedule(vector<vector<int>>& schedule) {// write code heresort(schedule.begin(), schedule.end());int start -1, end 0;for (auto & nums : schedule){end…...

运行Zr.Admin项目(后端)

1.下载Zr.Admin代码压缩包 https://codeload.github.com/izhaorui/Zr.Admin.NET/zip/refs/heads/main 2.打开项目 我这里装的是VS2022社区版 进入根目录&#xff0c;双击ZRAdmin.sln打开项目 3.安装.net7运行时 我当时下载的代码版本是.net7的 点击安装 点击安装&#xff0…...