Linux系统编程:线程控制
目录
一. 线程的创建
1.1 pthread_create函数
1.2 线程id的本质
二. 多线程中的异常和程序替换
2.1 多线程程序异常
2.2 多线程中的程序替换
三. 线程等待
四. 线程的终止和分离
4.1 线程函数return
4.2 线程取消 pthread_cancel
4.3 线程退出 pthread_exit
4.4 线程分离 pthread_detach
五. 总结
一. 线程的创建
1.1 pthread_create函数
函数原型:int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(start_routine)(void*), void *args)
函数功能:创建新线程
函数参数:
thread -- 输出型参数,用于获取新线程的id
attr -- 设置线程属性,一般采用nullptr,表示为默认属性
start_routine -- 新创建线程的入口函数
args -- 传入start_routine函数的参数
返回值:成功返回0,失败返回对应错误码
关于pthread系列函数的错误检查问题:
- 一般的Linux系统调用相关函数,都是成功返回0,失败返回-1。
- 但函数pthread系列函数不是,这些函数都是成功返回0,失败返回错误码,不对全局错误码进行设置。
代码1.1演示了如何通过pthread_create函数创建线程,在主函数中,分别以%lld和%x的方式输出子线程id,图1.1为代码的运行结果。
代码1.1:创建线程
#include <iostream>
#include <cstdio>
#include <cstring>
#include <pthread.h>
#include <unistd.h>// 新建线程的入口函数
void *threadRoutine(void *args)
{while(true){std::cout << (char*)args << std::endl;sleep(1);}return nullptr;
}int main()
{pthread_t tid; // 接收子线程id的输出型参数// 调用pthread_create函数创建线程// tid接收新线程的id,nullptr表示新线程为默认属性// 新线程的入口函数设为threadRoutine,参数为"thread 1"int n = pthread_create(&tid, nullptr, threadRoutine, (char*)"thread 1");if(n != 0) // 检验新线程是否创建成功{std::cout << "error:" << strerror(n) << std::endl;exit(1);}while(true){printf("main thread, tid = %lld 0x%x\n", tid, tid);sleep(1);}return 0;
}
![](https://img-blog.csdnimg.cn/7cf3c58bb66c425686211cde1837bf5f.png)
1.2 线程id的本质
如1.2所示,在Linux的线程库pthread中,提供了用于维护每个线程的属性字段,包括描述线程的结构体struct pthread、线程的局部存储、线程栈等,用于对每个线程的维护。
每个线程在线程库中用于维护它的属性字段的起始地址,就是这个线程的id,换言之,线程id就是动态库(地址空间共享区)的一个地址,Linux为64位环境,因此,代码1.1输出的线程id会很大,这个值就对应地址空间共享区的位置。
为了保证每个线程的栈区是独立的,Linux采用的方法是线程栈在用户层提供,这样每个线程都会在动态线程库内部分得一块属于自身的“栈区”,这样就可以保证线程栈的独立性,而主线程的栈区,就使用进程地址空间本身的栈区。
Linux保证线程栈区独立性的方法:
- 子线程的栈区在用户层提供。
- 主线程栈区采用地址空间本身的栈区。
线程id的本质:地址空间共享区的一个地址。
![](https://img-blog.csdnimg.cn/32ecc59daeca4c34bae0e3144c1584a4.png)
二. 多线程中的异常和程序替换
2.1 多线程程序异常
在多线程程序中,如果某个线程在执行期间出现了异常,那么整个进程都可能会退出,在多线程场景下,任意一个线程出现异常,其影响范围都是整个进程。
如代码2.1创建了2个子线程,其中threadRun2函数中人为创造除0错误引发异常,发现整个进程都退出了,不会出现只有一个线程终止的现象。
结论:任意一个线程出现异常,其影响范围都是整个进程,会造成整个进程的退出。
代码2.1:多线程程序异常
#include <iostream>
#include <pthread.h>
#include <unistd.h>void *threadRoutine1(void *args)
{while(true){std::cout << (char*)args << std::endl;sleep(1);}return nullptr;
}void *threadRoutine2(void *args)
{while(true){std::cout << "thread 2, 除0错误!" << std::endl;int a = 10;a /= 0; }return nullptr;
}int main()
{pthread_t tid1, tid2;//先后创建线程1和2pthread_create(&tid1, nullptr, threadRoutine1, (void*)"thread 1");sleep(1);pthread_create(&tid2, nullptr, threadRoutine2, (void*)"thread 2");while(true){std::cout << "main thread ... ... " << std::endl;sleep(1);}return 0;
}
![](https://img-blog.csdnimg.cn/eddf2aaceb964766bf3aa277df4800aa.png)
2.2 多线程中的程序替换
与多线程中线程异常类似,多线程中某个线程如果进行了程序替换,那么并不会出现这个线程去运行新的程序,其他线程正常执行原来的工作的情况,而是整个进程都被替换去执行新的程序。
代码2.2在threadRoutine1函数中通过execl去执行系统指令ls,运行代码我们发现,在子线程中进行程序替换后,主线程也不再继续运行了,进程执行完ls指令,就终止了。
结论:多线程程序替换是整个进程都被替换,而不是只替换一个线程。
代码2.2:多线程程序替换
#include <iostream>
#include <cstdio>
#include <cstring>
#include <pthread.h>
#include <unistd.h>void *threadRoutine1(void *args)
{while(true){std::cout << (char*)args << std::endl;execl("/bin/ls", "ls", nullptr); // 子线程中进行程序替换exit(0);}return nullptr;
}int main()
{pthread_t tid;// 创建线程int n = pthread_create(&tid, nullptr, threadRoutine1, (void*)"thread 1");if(n != 0) {// 检验线程创建成功与否std::cout << strerror(n) << std::endl;exit(1);}while(true){std::cout << "main thread" << std::endl;sleep(1);}return 0;
}
![](https://img-blog.csdnimg.cn/f669fc696ce4487ba73109887d3ced46.png)
三. 线程等待
线程等待与进程等待类似,主线程需要等待子线程退出,以获取子线程的返回值。如果主线程不等待子线程,而主线程也不退出,那么子线程就会处于“僵尸状态”,其task_struct一直得不到释放,引起内存泄漏。
- 通过pthread_join函数,可以实现对线程的等待。
- 线程等待只能是阻塞等待,不能非阻塞等待。
pthread_join函数 -- 等待线程
函数原型:int pthread_join(pthread_t thread, void **ret);
函数参数:
thread -- 等待线程的id
ret -- 输出型参数,获取线程函数的返回值
返回值:成功返回0,失败返回错误码
在代码3.1中, 线程函数threadRoutine中在堆区new了5个int型数据的空间,并赋值为1~5,线程函数返回指向这块堆区资源的指针,主线程等待子线程退出,主线程可以看到这块资源。注意线程函数返回值的类型为void*,使用返回值的时候要注意强制类型转换。
代码3.1:pthread_join线程等待
#include <iostream>
#include <cstdio>
#include <cstring>
#include <pthread.h>
#include <unistd.h>void *threadRoutine(void *args)
{std::cout << (char*)args << std::endl;int *pa = new int[5];for(int i = 0; i < 5; ++i){pa[i] = i + 1;}return (void*)pa;
}int main()
{pthread_t tid;pthread_create(&tid, nullptr, threadRoutine, (void*)"thread 1");int *pa = nullptr;// 等待线程退出,pa接收线程函数返回值pthread_join(tid, (void**)&pa);// 获取线程函数返回值指向的空间内的资源std::cout << "thread exit" << std::endl;for(int i = 0; i < 5; ++i){printf("pa[%d] = %d\n", i, pa[i]);}delete[] pa;return 0;
}
![](https://img-blog.csdnimg.cn/7e269f7d39ee4c5fa1b2c57d275170af.png)
四. 线程的终止和分离
可以实现线程终止的方法有:
- 线程函数return。
- 由另一个线程将当前线程取消pthread_cancel。
- 线程退出pthread_exit。
4.1 线程函数return
pthread_create函数的第三个参数start_routine为线程函数指针,新创建的线程就负责执行这个函数,如果这个函数运行完毕return退出,那么,线程就退出了。
但是这种方法对主线程不适用,如果主线程退出,就是进程终止了,全部线程都会退出。
结论:如果线程函数return,那么线程就退出了,但主线程return进程就退出了,不适用这种退出方式。
线程函数接收一个void*类型的参数,返回void*类型参数,如果线程函数运行到了return,那么这个线程就退出了,如代码3.1中的threadRoutine,就是采用return来终止线程的。
代码4.1验证了主线程退出的情况,设定线程函数为死循环IO输出,但是主线程在创建完子线程sleep(2)之后return,发现线程函数并没有继续运行,证明了主线程退出不适用于return这种方法来终止。
代码4.1:验证主线程不能通过return退出
// 线程函数死循环
void *threadRoutine1(void *args)
{while(true){std::cout << (char*)args << std::endl;sleep(1);}return nullptr;
}int main()
{pthread_t tid;// 创建线程int n = pthread_create(&tid, nullptr, threadRoutine1, (void*)"thread 1");std::cout << "main thread" << std::endl;sleep(2); // 主线程sleep 2s后退出return 5;
}
![](https://img-blog.csdnimg.cn/677188f3f6f24675a4cccd52600c0cf6.png)
4.2 线程取消 pthread_cancel
pthread_cancel函数可用于通过指定线程id,来取消线程。
pthread_cancel -- 取消线程
函数原型:int pthread_cancel(pthread_t thread)
函数参数:thread -- 被取消的线程的id
返回值:成功返回0,不成功返回非0的错误码
一般而言,采用主线程取消子线程的方式来取消线程,一个线程取消自身也是可以的,但一般不会这样做,pthread_cancel(pthread_self()) 可用于某个线程取消其自身,其中pthread_self函数的功能是获取线程自身的id。
- pthread_self函数 -- 获取线程自身的id。
如果一个线程被取消了,那么就无需在主线程中通过pthread_join对这个线程进行等待,但如果使用了pthread_join对被取消的线程进行等待,那么pthread_join的第二个输出型参数会记录到线程函数的返回值为-1。
结论:如果一个线程被pthread_cancel了,那么pthread_join会记录到线程函数返回(void*)-1。
在代码4.2中,通过pthread_cancel函数,取消子线程,然后pthread_join等待子线程,输出强转为long long类型的返回值ret,记录到ret的值为-1。
代码4.2:取消子线程并等待取消了的子线程
// 线程函数
void *threadRoutine1(void *args)
{while(true){std::cout << (char*)args << std::endl;sleep(1);}return (void*)10;
}int main()
{pthread_t tid;// 创建线程pthread_create(&tid, nullptr, threadRoutine1, (void*)"thread 1");std::cout << "main thread" << std::endl;sleep(2); pthread_cancel(tid); // 取消id为tid的子线程void *ret = nullptr;int n = pthread_join(tid, &ret); // 等待已经取消的线程退出std::cout << "ret : " << (long long)ret << std::endl;return 0;
}
![](https://img-blog.csdnimg.cn/af34dfc442b04c38aca85aafcad45bb2.png)
4.3 线程退出 pthread_exit
pthread_exit 函数在线程函数中,可用于指定线程函数的返回值并退出线程,与return的功能基本完全相同,注意,exit不可用于退出线程,在任何一个线程中调用exit,都在让整个进程退出。
pthread_exit 函数 -- 让某个线程退出
函数原型:void pthread_exit(void *ret)
函数参数:ret -- 线程函数的退出码(返回值)
代码4.3在线程函数中调用pthread_exit终止线程,指定返回值为(void*)111,在主线程中等待子线程,并将线程函数返回值存入ret中,输出(long long)ret的值,证明子线程返回(void*)111。
代码4.3:通过pthread_exit终止线程
#include <iostream>
#include <cstdio>
#include <cstring>
#include <pthread.h>
#include <unistd.h>// 线程函数
void *threadRoutine1(void *args)
{int count = 0;while(true){std::cout << (char*)args << ", count:" << ++count << std::endl;if(count == 3) pthread_exit((void*)111);sleep(1);}return nullptr;
}int main()
{pthread_t tid;// 创建线程pthread_create(&tid, nullptr, threadRoutine1, (void*)"thread 1");std::cout << "main thread" << std::endl;sleep(5); void *ret = nullptr;pthread_join(tid, &ret); std::cout << "[main thread] child thread exit, ret:" << (long long)ret << std::endl;return 0;
}
![](https://img-blog.csdnimg.cn/f65f646a9de845a284ec57ce6b61dcdd.png)
4.4 线程分离 pthread_detach
严格意义上讲,pthread_detach并不算线程退出。即使一个线程函数中使用了pthread_detach(pthread_self())对其自身进行分离,线程函数在pthread_detach之后的代码也会正常被执行。
pthread_detach一般用于不需要关心退出状态的线程,被pthread_detach分离的子线程,即使主线程不等待子线程退出,子线程也不会出现僵尸问题。
一般来说,都是线程分离其自身,当然也可以通过主线程分离子线程,但不推荐这么做。
经pthread_detach分离之后的线程,不应当pthread_join等待,如果等待一个被分离的线程,那么pthread_join函数会返回错误码。
结论:(1).pthread_detach用于将不需要关系关系退出状态的子线程分离 (2).被分离的线程不应被等待,如果被等待,那么pthread_join会返回非0错误码。
代码4.4演示了经pthread_detach分离之后线程函数继续运行,等待被分离的线程失败的情景。
代码4.4:线程分离及等待被分离的线程
#include <iostream>
#include <cstdio>
#include <cstring>
#include <pthread.h>
#include <unistd.h>// 线程函数
void *threadRoutine1(void *args)
{// 子线程将其自身分离pthread_detach(pthread_self());int count = 0;while(true){std::cout << (char*)args << ", count:" << ++count << std::endl;if(count == 3) pthread_exit((void*)111);sleep(1);}return (void*)10;
}int main()
{pthread_t tid;// 创建线程pthread_create(&tid, nullptr, threadRoutine1, (void*)"thread 1");std::cout << "main thread" << std::endl;sleep(5); void *ret = nullptr;int n = pthread_join(tid, &ret); // 等待已经取消的线程退出 if(n != 0) // 检验是否等待成功{std::cout << "wait thread error -> " << strerror(n) << std::endl;}return 0;
}
![](https://img-blog.csdnimg.cn/289dcdbb1a944324b1d667f1e05aec2f.png)
五. 总结
- pthread_create函数可以创建子线程,关于线程的管理方法及属性字段,被记录在动态库里,线程id本质上就是地址空间共享区的某个地址。
- 由于Linux在系统层面不严格区分进程和线程,CPU调用只认PCB,因此为了保证每个线程栈空间的独立性,子线程的栈由用户层(动态库)提供,主线程的栈区就是地址空间的栈区。
- 在多线程中,任何一个线程出现异常,影响范围都是整个进程,如果在某个线程中调用exec系列函数替换程序,那么整个进程都会被替换掉。
- pthread_join的功能为在主线程中等待子线程,如果子线程没有被detach且不被主线程等待,那么子线程就会出现僵尸问题。
- 有三种方法可以终止线程:(1). 线程函数return,这种方法不适用于主线程。(2). pthread_exit 函数终止线程函数。(3). pthread_cancel 取消线程,被取消的线程不需要被等待,如果等待会记录到线程函数返回(void*)-1。
- 如果某个子线程的退出状态不需要关心,那么就可以通过pthread_detach分离子线程,分离后的线程不应被等待,如果被等待,那么pthread_join函数就会返回非零错误码。
相关文章:
![](https://img-blog.csdnimg.cn/289dcdbb1a944324b1d667f1e05aec2f.png)
Linux系统编程:线程控制
目录 一. 线程的创建 1.1 pthread_create函数 1.2 线程id的本质 二. 多线程中的异常和程序替换 2.1 多线程程序异常 2.2 多线程中的程序替换 三. 线程等待 四. 线程的终止和分离 4.1 线程函数return 4.2 线程取消 pthread_cancel 4.3 线程退出 pthread_exit 4.4 线程…...
![](https://img-blog.csdnimg.cn/1f908c2049d24f0b99fb2a207e55cb1e.png)
基于Java+SpringBoot+Vue前后端分离纺织品企业财务管理系统设计和实现
博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…...
![](https://www.ngui.cc/images/no-images.jpg)
搭建开发环境-Windows
写C# 的请出去。 然后,Windows 是最好的Linux发行版。搭建开发环境-WSLUbuntu...
![](https://img-blog.csdnimg.cn/94d116f7e3c641ccab451b9cdfdf9364.png)
【 Python 全栈开发 - 人工智能篇 - 45 】集成算法与聚类算法
文章目录 一、集成算法1.1 概念1.2 常用集成算法1.2.1 Bagging1.2.2 Boosting1.2.2.1 AdaBoost1.2.2.2 GBDT1.2.2.3 XgBoost 1.2.3 Stacking 二、聚类算法2.1 概念2.2 常用聚类算法2.2.1 K-means2.2.2 层次聚类2.2.3 DBSCAN算法2.2.4 AP聚类算法2.2.5 高斯混合模型聚类算法 一、…...
![](https://www.ngui.cc/images/no-images.jpg)
SSM商城项目实战:账户充值功能实现
SSM商城项目实战:账户充值功能实现 在一个电商平台中,用户账户充值是一个非常重要的功能。本文将介绍如何在SSM(SpringSpringMVCMyBatis)商城项目中实现账户充值功能。通过本文的指导,你将学会如何在项目中添加账户充…...
![](https://www.ngui.cc/images/no-images.jpg)
wireshark工具pcap文件转换
pcap详解_pcap_loop_小虎随笔的博客-CSDN博客 分析802.11无线报文hexdump内容:利用wireshark自带二进制工具text2pcap将hexdump内容转换为pcap文件..._weixin_30835933的博客-CSDN博客 text2pcap: 将hex转储文本转换为Wireshark可打开的pcap文件(wireshark,数据) …...
![](https://img-blog.csdnimg.cn/a2e1d38159d04acfa0ccdfb1eedd91b9.png#pic_center)
Python+TinyPNG熊猫网站自动化的压缩图片
前言 本篇在讲什么 PythonTinyPNG自动化处理图片 本篇需要什么 对Python语法有简单认知 依赖Python2.7环境 依赖TinyPNG工具 本篇的特色 具有全流程的图文教学 重实践,轻理论,快速上手 提供全流程的源码内容 ★提高阅读体验★ 👉…...
![](https://img-blog.csdnimg.cn/6af88c25a61341c6b01f257b931670d6.png)
【Linux】socket 编程基础
文章目录 📕 网络间的通信📕 socket 是什么1. socket 套接字2. 套接字描述符3. 基本的 socket 接口函数3.1 头文件3.2 socket() 函数3.3 bind() 函数struct sockaddr主机序列与网络序列 3.4 listen() 函数3.5 connect() 函数3.6 accept() 函数IP 地址风格…...
![](https://img-blog.csdnimg.cn/img_convert/8dfe738dcb63176bd275dc4ea5298ea1.jpeg)
openGauss学习笔记-51 openGauss 高级特性-列存储
文章目录 openGauss学习笔记-51 openGauss 高级特性-列存储51.1 语法格式51.2 参数说明51.3 示例 openGauss学习笔记-51 openGauss 高级特性-列存储 openGauss支持行列混合存储。行存储是指将表按行存储到硬盘分区上,列存储是指将表按列存储到硬盘分区上。 行、列…...
![](https://img-blog.csdnimg.cn/f54755ad1b7b448cab91050592060665.png#pic_center)
ReactNative 密码生成器实战
效果展示图 使用插件 Formik 负责表单校验、监听表单提交、数据校验错误信息展示 Yup 负责表单校验规则 分析页面 从上述的展示图我们可以看到的主要元素有:输入框、单选按钮和按钮。其中生成的密码长度不可能很大也不可能为负数和 0,所以我们可以限…...
![](https://img-blog.csdnimg.cn/16a0584fd8084efb9095bb02387cf934.png)
开始MySQL之路——外键关联和多表联合查询详细概述
多表查询和外键关联 实际开发中,一个项目通常需要很多张表才能完成。例如,一个商城项目就需要分类表,商品表,订单表等多张表。且这些表的数据之间存在一定的关系,接下来我们将在单表的基础上,一起学习多表…...
![](https://www.learnfk.com/guide/images/wuya.png)
无涯教程-PHP - intval() 函数
PHP 7引入了一个新函数 intdiv(),该函数对其操作数执行整数除法并将该除法返回为int。 <?php$valueintdiv(10,3);var_dump($value);print(" ");print($value); ?> 它产生以下浏览器输出- int(3) 3 PHP - intval() 函数 - 无涯教程网无涯教程网…...
![](https://img-blog.csdnimg.cn/560e1e21002943d28d3375e2c034f49d.png)
2023年国赛数学建模思路 - 案例:粒子群算法
文章目录 1 什么是粒子群算法?2 举个例子3 还是一个例子算法流程算法实现建模资料 # 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 什么是粒子群算法? 粒子群算法(Pa…...
![](https://img-blog.csdnimg.cn/83e3de42d04c462eb81bca1fa7e319df.png)
【1++的数据结构】之map与set(一)
👍作者主页:进击的1 🤩 专栏链接:【1的数据结构】 文章目录 一,关联式容器与键值对二,setset的使用 三,mapmap的使用 四,multiset与multimap 一,关联式容器与键值对 像l…...
![](https://img-blog.csdnimg.cn/cb869868ff2847a7a716d70bd00a3527.png)
Ubuntu断电重启后黑屏左上角光标闪烁,分辨率低解决办法,ubuntu系统display只有4:3 怎么办?太卡
这个问题主要是显卡驱动问题,按照步骤更新显卡驱动 1,选择metapackage 并且选择proprietary版本,选择版本号选择最新的版本。 2,具体步骤参考 前言 笔者在安装显卡驱动时并未遇到问题,主要是后续屏幕亮度无法调节&…...
![](https://www.ngui.cc/images/no-images.jpg)
Java 微服务当中POST form 、url、json的区别
在Java微服务的Controller中,你可以处理来自客户端的不同类型的POST请求,包括POST form、POST URL参数和POST JSON数据。以下是它们的区别以及在微服务Controller中的示例说明: POST Form 表单数据: 当客户端以表单方式提交数据…...
![](https://www.ngui.cc/images/no-images.jpg)
repo 常用命令汇总——202308
文章目录 1. 下载repo:2. 获取工程repo信息3. 下载代码4. 创建并切换本地分支5. repo forall6. repo upload7. repo list8. repo info9. repo help 1. 下载repo: 使用下面命令,具体版本号参考前面网页中显示的最新版本号。 curl http://git…...
![](https://img-blog.csdnimg.cn/img_convert/19270880a25074f42260e9062c83a050.png)
[Linux]命令行参数和进程优先级
[Linux]命令行参数和进程优先级 文章目录 [Linux]命令行参数和进程优先级命令行参数命令行参数的概念命令函参数的接收编写代码验证 进程优先级进程优先级的概念PRI and NI使用top指令修改nice值 命令行参数 命令行参数的概念 命令行参数是指用于运行程序时在命令行输入的参数…...
![](https://img-blog.csdnimg.cn/0665075459554700aa59cc667bbf5c78.png)
Android13新特性之通知权限提升
Android13新特性之通知权限提升 随着移动通信的高速发展,保障通信的安全性变得尤为重要。在Android 13的最新版本中,通知权限的管理得到了进一步加强。为了实现安全的通信和确保用户的隐私,必须正确申请通知权限。本文将详细探讨如何在Andro…...
![](https://img-blog.csdnimg.cn/a003105f10d9473c9ff071ce56525eb3.png)
206. 反转链表 (简单系列)
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2: 输入:head [1,2] 输出:[2,1] 示例 3: 输…...
![](https://img-blog.csdnimg.cn/fe9916bf69a0446a8044703f6d8e073e.png)
攻防世界-Fakebook
原题 解题思路 点击join就可以进行注册 username看起来是个超链,点击跳转 在url里出现了no1,看起来可以注入,改成no1 and 12报错。本来想用sqlmap,可能是网速有问题,啥都没出来。no1order by 5报错,一共有…...
![](https://img-blog.csdnimg.cn/e96d879826d143b9950c5cf7ab524f87.png)
0基础入门C++之类和对象下篇
目录 1.再谈构造函数1.1构造函数赋值1.2初始化列表1.3explicit关键字 2.static成员2.1概念2.1静态成员变量2.2静态成员函数2.3特性 3.匿名对象4.友元函数4.1友元函数4.2友元类 5.内部类6.再次理解类和对象 1.再谈构造函数 首先我们先来回忆一下构造函数: 构造函数是…...
![](https://www.ngui.cc/images/no-images.jpg)
ECMAScript 2023
从尾到头搜索数组 在 JavaScript 中,通过 find() 和 findIndex() 查找数组中的值是一种常见做法。不过,这些方法从数组的开始进行遍历: const array [{v: 1}, {v: 2}, {v: 3}, {v: 4}, {v: 5}];array.find(elem > elem.v > 3); // {v:…...
![](https://img-blog.csdnimg.cn/594862bc3ede41e49ae60de20a513257.png)
爬虫实战之使用 Python 的 Scrapy 库开发网络爬虫详解
关键词 - Python, Scrapy, 网络爬虫 在信息爆炸时代,我们每天都要面对海量的数据和信息。有时候我们需要从互联网上获取特定的数据来进行分析和应用。今天我将向大家介绍如何使用 Python 的 Scrapy 库进行网络爬虫,获取所需数据。 1. Scrapy 简介 1.1 …...
![](https://img-blog.csdnimg.cn/782a15c45c094291ab56d4c709b76352.png)
【面试题】UDP和TCP有啥区别?
UDP UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就…...
![](https://www.ngui.cc/images/no-images.jpg)
字节实习后端面试总结(C++/GO)
语言 C ++, Python 哪一个更快? 答:这个我不知道从哪方面说,就是 C + + 的话,它其实能够提供开发者非常多的权限,就是说它能涉及到一些操作系统级别的一些操作,速度应该挺快。然后 Python 实现功能还是蛮快的。 补充: 一般而言,C++更快一些,因为它是一种编译型语…...
![](https://www.ngui.cc/images/no-images.jpg)
linux 自动登录SSH
自动登录SSH 每次ssh连接服务器还要输入密码,可以进行配置自动登录SSH 步骤 在SSH的client端产生一组公钥和私钥 # 算法可以使用RSA和DSA两种ssh-keygen -f 秘钥文件名 -t 使用的算法 会生成私钥文件id_rsa以及公钥文件id_rsa.pub 把公钥上传至SSH Server端的.ssh目…...
![](https://img-blog.csdnimg.cn/f19327d725484bfeb7de3b4f71038d3c.png)
量化:pandas基础
文章目录 简介Series构造 DataFrame构造列的查改增删填充默认值 简介 pandas是 Python 的核心数据分析支持库,提供了快速、灵活、明确的数据结构。 pandas主要的两种数据结构为Series和DataFrame,分别用于处理一维和二维数据。 Series Series 是一种类…...
![](https://img-blog.csdnimg.cn/img_convert/46d09a9a4de6ef73d07715fa5953b323.png)
华为云渲染实践
// 编者按:云计算与网络基础设施发展为云端渲染提供了更好的发展机会,华为云随之长期在自研图形渲染引擎、工业领域渲染和AI加速渲染三大方向进行云渲染方面的探索与研究。本次LiveVideoStackCon 2023上海站邀请了来自华为云的陈普,为大家分…...
![](https://www.ngui.cc/images/no-images.jpg)
SpringBoot注解详解:从核心到Web,从数据到测试,一网打尽
总结的了平时学习springboot常用的一些注解,方便以后开发时可以阅览回忆 springboot的常用注解可以分为以下几类: 核心注解:这些注解是springboot的基础,用于启动、配置和管理springboot应用。Web MVC注解:这些注解是…...
![](https://img2018.cnblogs.com/blog/1210508/201901/1210508-20190105192708374-440752647.jpg)
石家庄代理注册公司/香港seo公司
转载于:https://www.cnblogs.com/itfat/p/10225774.html...
![](/images/no-images.jpg)
信息类网站怎么做/重庆网络推广平台
先来解释下什么是错误缓冲区?在MySQL里面, 错误缓冲区只记录最近一次出现的错误, 只要是有新的错误产生,旧的就会被覆盖掉。 所以想知道产生了什么错误,就得在每个有可能发生错误的语句后面紧跟着"show warnings&…...
![](/images/no-images.jpg)
商务型网站有哪些/seo知识分享
1.应用场景 c语言精通了能干什么? 1、C语言是许多高级计算机语言的基础,学好C语言能更好的学习其他高级语言,为以后的学习打基础;往深学C语言的话那就是学到C在Linux里的应用,Linux十分强大,可以百度了解。 2、C语言是…...
![](https://s1.51cto.com/wyfs02/M00/A2/89/wKioL1mhiBGiOt4UAABjzehyDw0706.png)
北京南站是丰台站吗/火蝠电商代运营公司
问答:1.你理解的python是什么?为什么会使用python?稍微比别的语言简单点,linux自动化运维需要2. 解释python第一行怎么写?写的内容是做什么的?怎么写可移植性强?为什么?#!/usr/bin/env python 说明环境,解释器 ,用这种方法写…...
![](/images/no-images.jpg)
翻译网站怎么做/网站如何做优化推广
来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/print-in-order著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 package www;import java.util.concurrent.CompletableFuture; im…...
![](/images/no-images.jpg)
wordpress游戏评测站睡觉/怎么提高seo关键词排名
题目链接:https://www.nowcoder.net/acm/contest/75/E 题目描述:给定一个整数N(0≤N≤10000),求取N的阶乘 输入描述:多个测试数据,每个测试数据输入一个数N 输出描述:每组用一行输出N的阶乘 输入 1 2 3 输出…...