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

【hello Linux】线程概念

目录

1. 线程概念的铺设 

2. Linux线程概念

2.1 什么是线程

2.2 线程的优点

2.3 线程的缺点

2.4 线程异常

2.5 线程用途

3. Linux进程VS线程

4. Linux线程控制

4.1 POSIX线程库

4.2 创建线程

4.3 进程ID和线程ID

4.4 线程终止

4.5 线程等待

4.6 分离线程


Linux🌷 

1. 线程概念的铺设 

在我们之前的学习中都是一个进程对应一个执行流,也就是说进程是OS分配资源的基本单位,也是CPU调度的基本单位;

今天,我们便要学习一个进程对应一个执行流,或者是一个进程对应多个执行流的情况,这里的每个执行流便可称为一个线程;

也就是说一个进程内是可能存在多个线程的,进程与线程数之比=1:n;内核中有可能存在着大量的线程,OS便要对这些线程进行管理。“先描述再组织”是OS管理对象的一个准则,线程是通过线程控制块(TCB)描述的,这是常规的一些操作系统的做法,比如Windows;

在Linux中是没有专门为线程设计TCB的,而是用进程PCB来模拟线程。

下面用一张图来大概说明下线程与进程:

 对于线程来说只创建task_struct,将当前进程的资源(代码+数据)划分为若干份让每个task_struct用,每个task_struct就是一个需要被调度的执行流;对于CPU来说,此时看到的task_struct是小于原先的task_struct的,这里的task_struct也成为轻量级进程;多个线程是共享同一进程的地址空间的;

这样做不用维护复杂的进程和线程的关系,不用单独为线程设计任何算法,直接使用进程的一套相关的方法,OS只需要聚焦在线程间的资源分配上就好了;

进程的今昔对比:

  • 之前的进程,内部只有一个执行流;
  • 今天的进程,内部可以具有多个执行流;

Linux线程与接口关系的认识:

Linux中的线程是用进程模拟的,Linux中没有提供直接操作线程的接口,只是提供了在同一地址空间内创建task_struct的方法,分配资源给指定的task_struct的接口,这种方法对用户特别不友好,系统级别的工程师在用户层,对Linux轻量级进程接口进行了封装,给我们打包成了库,让用户直接使用库函数,这个库称为 原生线程库 是用户层的;

2. Linux线程概念

2.1 什么是线程

  • 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是一个进程内部的控制序列”;
  • 一切进程至少都有一个执行线程;
  • 线程在进程内部运行,本质是在进程地址空间内运行;
  • Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化;
  • 透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程执行流;

2.2 线程的优点

  • 创建一个新线程的代价要比创建一个新进程小得多;
  • 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多;
  • 线程占用的资源要比进程少很多;
  • 能充分利用多处理器的可并行数量;
  • 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务;
  • 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现;
  • I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作;

在这里要注意的一点是:

对于计算密集型应用,并不是说线程越多是越好的,一般线程的个数与CPU的核数相等即可,如果线程太多会导致被过度调度切换(有成本的),假如只有一个CPU划分了10个线程,这样的话还不如让一个进程直接在CPU上运行;

 对于IO密集型应用,IO是允许多一些线程,如果一个进程需要等待磁盘资源、IO资源,那么便可以将该进程分为多个线程,让等待这些资源的时间重叠,从而缩短整个等待时间。但也不是说越多越好的,因为磁盘只有一个,划分为再多的线程也只有排队等待同一个磁盘资源,无济于事;

2.3 线程的缺点

1. 性能损失

一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计

算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指

的是增加了额外的同步和调度开销,而可用的资源不变。

2. 健壮性降低

编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。

3. 缺乏访问控制

进程是访问控制的基本粒度,在一个线程中调用某些 OS 函数会对整个进程造成影响。
4. 编程难度提高
编写与调试一个多线程程序比单线程程序困难得多

2.4 线程异常

  • 单个线程如果出现除零,野指针等问题导致线程崩溃,进程也会随着崩溃;
  • 线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出;

2.5 线程用途

  • 合理的使用多线程,能提高CPU密集型程序的执行效率;
  • 合理的使用多线程,能提高IO密集型程序的用户体验(如生活中我们一边写代码一边下载开发工具,就是多线程运行的一种表现);

3. Linux进程VS线程

1. 进程和线程

  • 进程是资源分配的基本单位;
  • 线程是CPU调度的基本单位;
  • 线程共享进程数据,但也拥有自己的一部分数据:
    • 线程ID
    • 一组寄存器
    • errno
    • 信号屏蔽字
    • 调度优先级

在这最重要的是:栈和上下文;

栈保存临时数据,上下文用于CPU的调度切换; 

2. 进程的多个线程共享同一地址空间,因此Text SegmentData Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:

  • 文件描述符表;
  • 每种信号的处理方式(SIG_ IGNSIG_ DFL或者自定义的信号处理函数);
  • 当前工作目录;
  • 用户id和组id;
3. 进程和线程的关系如下图:

 4. Linux线程控制

4.1 POSIX线程库

  • 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的;
  • 要使用这些函数库,要通过引入头文<pthread.h>;
  • 链接这些线程函数库时要使用编译器命令的“-lpthread”选项;

4.2 创建线程

功能:创建一个新的线程原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)
(void*), void *arg);参数thread:输出型参数,返回线程ID;attr:设置线程的属性,attr为NULL表示使用默认属性;start_routine:是个函数地址,线程启动后要执行的函数;arg:传给线程启动函数的参数;返回值:成功返回0;失败返回错误码
错误检查:
  • 传统的一些函数是,成功返回0,失败返回-1,并且对全局变量errno赋值以指示错误;
  • pthreads函数出错时不会设置全局变量errno(而大部分其他POSIX函数会这样做)。而是将错误代码通过返回值返回;
  • pthreads同样也提供了线程内的errno变量,以支持其它使用errno的代码。对于pthreads函数的错误,建议通过返回值来判定,因为读取返回值要比读取线程内的errno变量的开销更小;
  #include <stdio.h>#include <pthread.h>#include <string.h>#include <unistd.h>#include <sys/types.h>void *thread_run(void *arg){int i;for(;;){printf("I am %s,pid:%d\n",(char*)arg,getpid());                                                    sleep(1);}}int main(){//用于接收新创建的线程的idpthread_t tid;//用于接收创建线程函数的返回值int ret;//创建线程if((ret=pthread_create(&tid,NULL,thread_run,(void*)"thread1"))!=0){printf("pthread_create:%s\n",strerror(ret));return 1;}//主执行流int i;for(;;){printf("I am main thread!pid:%d\n",getpid());sleep(1);}return 0;}

 4.3 进程ID和线程ID

  • Linux中,目前的线程实现是Native POSIX Thread Libaray,简称NPTL。在这种实现下,线程又被称为轻量级进程(Light Weighted Process),每一个用户态的线程,在内核中都对应一个调度实体,也拥有自己的进程描述符(task_struct结构体)
  • 没有线程之前,一个进程对应内核里的一个进程描述符,对应一个进程ID。但是引入线程概念之后,情况发生了变化,一个用户进程下管辖N个用户态线程,每个线程作为一个独立的调度实体在内核态都有自己的进程描述符,进程和内核的描述符一下子就变成了1N关系,POSIX标准又要求进程内的所有线程调用getpid函数时返回相同的进程ID,如何解决上述问题呢?
  • Linux内核引入了线程组的概念
struct task_struct {...pid_t pid;pid_t tgid;...struct task_struct *group_leader;...struct list_head thread_group;...
};
  • 多线程的进程,又被称为线程组,线程组内的每一个线程在内核之中都存在一个进程描述符(task_struct)与之对应。进程描述符结构体中的pid,表面上看对应的是进程ID,其实不然,它对应的是线程ID;进程描述符中的tgid,含义是Thread Group ID,该值对应的是用户层面的进程ID;

 查看线程ID:

ps -aL

强调一点:

线程和进程不一样,进程有父进程的概念,但在线程组里面,所有的线程都是对等关系。

在程序中,我们也可以使用函数的方式获得该线程自身的ID:

#include <pthread.h>pthread_t pthread_self(void);

 该函数获得的线程ID和刚才查出的线程ID是不同的,我们查到的线程ID是 pthread 线程库的线程ID,使用命令的方式查看的是Linux内核中的LWP,pthread库的线程ID是一个虚拟地址,如下图中的pthread_t id所示;

 4.4 线程终止

如果需要只终止某个线程而不终止整个进程 , 可以有三种方法:
  • 从线程函数return。这种方法对主线程不适用,main函数return相当于调用exit(终止整个进程);
  • 线程可以调用pthread_ exit终止自己;
  • 一个线程可以调用pthread_ cancel终止同一进程中的另一个线程;
pthread_exit函数:
功能:线程终止原型:void pthread_exit(void *value_ptr);参数:value_ptr:value_ptr不要指向一个局部变量。返回值:无返回值,跟进程一样,线程结束的时候无法返回到它的调用者(自身)
需要注意 ,pthread_exit 或者 return 返回的指针所指向的内存单元必须是全局的或者是用 malloc 分配
, 不能在线程函数的栈上分配, 因为当其它线程得到这个返回指针时线程函数已经退出了。

pthread_cancel函数:
功能:取消一个执行中的线程原型:int pthread_cancel(pthread_t thread);参数:thread:线程ID返回值:成功返回0;失败返回错误码

4.5 线程等待

线程等待的原因:

  • 已经退出的线程,其空间没有被释放,仍然在进程的地址空间内。
  • 创建新的线程不会复用刚才退出线程的地址空间。

pthread_join函数:

功能:等待线程结束原型:int pthread_join(pthread_t thread, void **value_ptr);参数:thread:线程ID;value_ptr:输出型参数,用来获取新线程推出时候的函数的返回值;返回值:成功返回0;失败返回错误码
调用该函数的线程将挂起等待 , 直到  id  为  thread  的线程终止。 thread 线程以不同的方法终止 , 通过
pthread_join  得到的终止状态是不同的,总结如下:
  • 如果thread线程通过return返回,value_ ptr所指向的单元里存放的是thread线程函数的返回值;
  • 如果thread线程被别的线程调用pthread_ cancel异常终掉,value_ ptr所指向的单元里存放的是常数PTHREAD_CANCELED((void*)-1)
  • 如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数;
  • 如果对thread线程的终止状态不感兴趣,可以传NULLvalue_ ptr参数;
  #include <stdio.h>    #include <pthread.h>    #include <unistd.h>    #include <stdlib.h>    void *thread1( void *arg )    {    printf("thread 1 returning ... \n");    int *p = (int*)malloc(sizeof(int));    *p = 1;    return (void*)p;    }    void *thread2( void *arg )    {    printf("thread 2 exiting ...\n");    int *p = (int*)malloc(sizeof(int));    *p = 2;    pthread_exit((void*)p);    }    void *thread3( void *arg )    {    while(1)    {    printf("thread 3 is running ...\n");    sleep(1);    }    return NULL;    }                                                                                                                                        int main()    {    pthread_t tid;    void *ret;    //thread1 return     //创建线程1    pthread_create(&tid, NULL, thread1, NULL);    //等待线程1    pthread_join(tid,&ret);    printf("thread return, thread id:%X, return code:%d\n",tid,*(int*)ret);    free(ret);    //thread2 exit    //创建线程2    pthread_create(&tid, NULL, thread2, NULL);    //等待线程2pthread_join(tid,&ret);printf("thread return, thread id:%X, return code:%d\n",tid,*(int*)ret);free(ret);//thread3 cancel by other//创建线程3pthread_create(&tid, NULL, thread3, NULL);sleep(3);pthread_cancel(tid);pthread_join(tid,&ret);if(ret==PTHREAD_CANCELED)printf("thread return, thread id:%X, return code:PTHREAD_CANELED\n");else printf("thread return, thread id:%X, return code:NULL\n",tid);return 0;}
在这里要提的一点是:

线程对于整个程序来说,根本上也是用函数的形式呈现的;

函数退出时有三种情况:

  • 1. 代码跑完结果正确;
  • 2. 代码跑完结果不正确;
  • 3. 代码异常;

对于上述3种情况,我们只 join 前两种,因为线程代码异常的话,OS会发信号给进程,整个进程就瘫痪了,无需考虑此情况;

4.6 分离线程

  • 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄漏;
  • 如果不关心线程的返回值,join是一种负担,这个时候,我们可以告诉系统,当线程退出时,自动释放线程资源。
int pthread_detach(pthread_t thread);
可以是线程组内其他线程对目标线程进行分离,也可以是线程自己分离:
pthread_detach(pthread_self());
joinable和分离是冲突的,一个线程不能既是joinable又是分离的。
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>void* thread_run(void *arg)
{pthread_detach(pthread_self());printf("%s\n",(char*)arg);return NULL;
}int main()
{pthread_t tid;if(pthread_create(&tid, NULL, thread_run, (void*)"thread1")!=0)                                       {printf("create thread error!\n");return 1;}int ret=0;//很重要,让新创建的线程先分离,在等待sleep(1);if(pthread_join(tid,NULL)==0){printf("pthread wait success!\n");ret=0;}else{printf("pthread wait failed!\n");ret=1;}return ret;
}

如果本篇博客对您有所收获的话,还请点赞👍、收藏🤏加关注🎈

相关文章:

【hello Linux】线程概念

目录 1. 线程概念的铺设 2. Linux线程概念 2.1 什么是线程 2.2 线程的优点 2.3 线程的缺点 2.4 线程异常 2.5 线程用途 3. Linux进程VS线程 4. Linux线程控制 4.1 POSIX线程库 4.2 创建线程 4.3 进程ID和线程ID 4.4 线程终止 4.5 线程等待 4.6 分离线程 Linux&#x1f337; 1…...

JavaWeb07(MVC应用01[家居商城]连接数据库)

目录 一.什么是MVC设计模式&#xff1f; 1.2 MVC设计模式有什么优点&#xff1f; 二.MVC运用&#xff08;家居商城&#xff09; 2.1 实现登录 2.2 绑定轮播【随机三个商品】 2.2.1 效果预览 index.jsp 2.3 绑定最新上架&热门家居 2.3.1 效果预览 2.3.2 代码实现 数据…...

如何使用电商API接口API接口如何应用

使用API接口 API&#xff08;应用程序接口&#xff09;是现代软件开发中必不可少的一部分&#xff0c;它通常允许软件与其他软件或服务进行交互。使用API可以大大提高软件的灵活性和可扩展性&#xff0c;并允许您轻松添加新的功能和服务&#xff0c;因此&#xff0c;API接口的…...

【移动端网页布局】流式布局案例 ⑥ ( 多排按钮导航栏 | 设置浮动及宽度 | 设置图片样式 | 设置文本 )

文章目录 一、多排按钮导航栏样式及核心要点1、实现效果2、总体布局设计3、设置浮动及宽度4、设置图片样式5、设置文本 二、完整代码实例1、HTML 标签结构2、CSS 样式3、展示效果 一、多排按钮导航栏样式及核心要点 1、实现效果 要实现下面的导航栏效果 ; 2、总体布局设计 该导…...

1. 先从云计算讲起

本章讲解知识点 什么是云计算&#xff1f; 为什么要用云计算&#xff1f; 物理服务器与云服务器对比 云计算服务类型 云计算部署类型 1. 什么是云计算&#xff1f; 云计算是一种通过计算机网络以服务的方式提供动态可伸缩的虚拟化资源的计算模式。按照服务层次分为IaaS、…...

ZooKeeper安装与配置集群

简介: ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件&#xff0c;它提供了一个分布式环境中的高可用性、高性能、有序访问的数据存储&#xff0c;可以让分布式应用程…...

浅谈Mysql的RR和RC隔离级别的主要区别

MySQL默认为RR级别 首先默认RR是因为mysql为了保证在主从同步过程中数据的安全的问题&#xff08;涉及到binlog三种格式&#xff09;。 就是说两个并发事务数AB&#xff0c;A先开启事物最后提交也是最后&#xff0c;事务B开启和提交都在A内部&#xff0c;由于隔离级别不同&…...

Build生成器模式

设计模式简述 设计模式的核心在于提供了相关问题的解决方案&#xff0c;使得人们可以更加简单方便地复用成功的设计和体系结构。 生成器模式&#xff08;创建型设计模式&#xff09; 意图&#xff1a;将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以…...

C++程序设计——常见C++11新特性

一、列表初始化 1.C98中{}的初始化问题 在C98中&#xff0c;允许使用花括号{}对数组元素进行统一的列表初始化值设定&#xff0c;比如&#xff1a; 但是对于一些自定义类型&#xff0c;就无法使用这样的方式进行初始化了&#xff0c;比如&#xff1a; 就无法通过编译&#xff…...

Rust main 函数返回值类型不能是 String

是的&#xff0c;Rust 的 main 函数返回值类型不能是 String。 Rust 的 main 函数只能返回以下几种类型之一&#xff1a; ()&#xff1a;表示空类型&#xff0c;不返回任何值。i32&#xff1a;表示程序的退出码&#xff0c;通常非零值表示执行失败&#xff0c;0 表示执行成功…...

视频里的音乐怎么转换成mp3格式?

视频里的音乐怎么转换成mp3格式&#xff1f;视频里的音乐转换为mp3的原因有很多&#xff0c;主要是因为mp3格式是一种音频格式&#xff0c;文件大小较小&#xff0c;更易于存储和传输。相比之下&#xff0c;视频格式则是一种视频文件格式&#xff0c;虽然包含音频&#xff0c;但…...

CSS3 grid网格布局

文章目录 CSS3 grid网格布局概述grid属性说明使用grid-template-rows & grid-template-columns 定义行高和列宽grid-auto-flow 定义项目的排列顺序grid-auto-rows & grid-auto-columns 定义多余网格的行高和列宽row-gap & column-gap 设置行间距和列间距gap 简写形…...

SPSS如何进行均值比较和T检验之案例实训?

文章目录 0.引言1.均值过程2.单样本T检验3.独立样本T检验4.成对样本T检验 0.引言 因科研等多场景需要进行数据统计分析&#xff0c;笔者对SPSS进行了学习&#xff0c;本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上相关资料进行学习笔记总结&#xff0c;本文对均值…...

Packet Tracer - 配置交换机端口安全

Packet Tracer - 配置交换机端口安全 地址分配表 设备 接口 IP 地址 子网掩码 S1 VLAN 1 10.10.10.2 255.255.255.0 PC1 NIC 10.10.10.10 255.255.255.0 PC2 NIC 10.10.10.11 255.255.255.0 非法笔记本电脑 NIC 10.10.10.12 255.255.255.0 目标 第 1 部…...

一图看懂 aiohttp 模块:基于 asyncio 的异步HTTP网络库, 资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 aiohttp 模块&#xff1a;基于 asyncio 的异步HTTP网络库, 资料整理笔记&#xff08;大全&#xff09; 摘要模块图类关系图模块全展开【aiohttp】统计常量模块1 aiohttp.hd…...

Linux + 香橙派 + V4L2 + http 实现远程监控摄像头在网页端显示

项目场景&#xff1a; 项目需求&#xff0c;需要做一个基于边缘端的人脸识别远程监控摄像头并在网页前端展示 &#xff0c;这里采用国产香橙派作为边缘计算终端&#xff0c;安装ubuntu系统&#xff0c;系统中采用v4l2接口对摄像头进行获取&#xff0c;当客户端通过网页进行请求…...

《编码——隐匿在计算机软硬件背后的语言》精炼——第15-16章(十六进制,RAM)

“学习如春起之苗&#xff0c;不见其增&#xff0c;日有所长。” —— 宋代朱熹 文章目录 十六进制十六进制概述十六进制表字节到十六进制 存储器特定的读功能特定的写功能RAM大型RAM阵列 十六进制 十六进制概述 十六进制是一种适用于计算机的进制法。在十进制中&#xff0c;…...

leetcode.1376 通知所有员工所需的时间 - bfs/dfs + 树

1376. 通知所有员工所需的时间 目录 一、bfs 二、dfs 题目&#xff1a; 公司里有 n 名员工&#xff0c;每个员工的 ID 都是独一无二的&#xff0c;编号从 0 到 n - 1。公司的总负责人通过 headID 进行标识。在 manager 数组中&#xff0c;每个员工都有一个直属负责人&#x…...

AtCoder Beginner Contest 300——A-G题讲解

蒟蒻来讲题&#xff0c;还望大家喜。若哪有问题&#xff0c;大家尽可提&#xff01; Hello, 大家好哇&#xff01;本初中生蒟蒻讲解一下AtCoder Beginner Contest 300这场比赛的A-G题&#xff01; A - N-choice question 原题 Problem Statement Given integers A A A and…...

Go:值与指针

1. 计算机中的值 在百万年的演化历史中&#xff0c;人类对事物的属性进行了抽象&#xff0c;有了数量、精度、信息等概念的表示&#xff0c;对应的我们称之为整数、小数、文本文字等。计算机出现后&#xff0c;我们使用计算机对真实世界的问题进行建模&#xff0c;通过计算机的…...

【Linux】进程学习(2)---理解进程操作

文章目录 查看进程通过系统目录查看通过ps命令查看 通过系统调用获取进程标识符通过系统调用创建进程初识fork函数fork函数的返回值 进程状态阻塞与运行状态Linux内核源码中的进程状态运行状态-R浅度睡眠状态-S深度睡眠状态-D暂停状态-T僵尸状态-Z死亡状态-X 查看进程 通过系统…...

基于springcloud实现的医院信息系统

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 医疗信息就诊系统&#xff0c;系统主要功能按照数据流量、流向及处理过程分为临床诊疗、药品管理、财务管理、患者管理。诊疗活动由各工作站配合完成&#xff0c;并将临床信息进行整理、处理、汇总、统计、分析等。本系统包括以…...

设计模式-创建型模式-(工厂、简单工厂、抽象工厂)

一、简单工厂模式 上代码 public class FoodFactory {public static Food makeFood(String name) {if (name.equals("noodle")) {Food noodle new LanZhouNoodle();noodle.addSpicy("more");return noodle;} else if (name.equals("chicken")…...

JAVA12新特性

JAVA12新特性 概述 2019年3月19日,java12正式发布了,总共有8个新的JEP(JDK Enhancement Proposals) JDK 12 is the open-source reference implementation of version 12 of the Java SE12 Platform as specified by by JSR 386 in the Java Community Process. JDK 12 reac…...

Nginx 静态文件、反向代理、负载均衡、缓存、SSL/TLS 加密、gzip 压缩 等等

Nginx的功能 1. 静态文件服务器2. 反向代理服务器3. 负载均衡4. 缓存5. SSL/TLS 加密6. URL 重写7. HTTP/28. WebSocket9. 反向代理缓存10. 安全限制11. gzip 压缩12. 请求限速13. 日志记录14. SSL 证书续订 Nginx 是一个高性能的开源 Web 服务器和反向代理服务器&#xff0c;它…...

Linux设备驱动模型(一)

一、sysfs文件系统 sysfs是一个虚拟文件系统&#xff0c;将内核总的设备对象的链接关系&#xff0c;以文件目录的方式表示出来&#xff0c;并提对设备提供读写接口。 二、kobject kobject是内核中对象表示的基类&#xff0c;可以认为所有的内核对象都是一个kobject kobject单…...

【Python入门篇】——Python基础语法(标识符与运算符)

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; Python入门&#xff0c;本专栏主要内容为Python的基础语法&#xff0c;Python中的选择循环语句…...

扩展 VirtualBox 已分配磁盘的方法

扩展 VirtualBox 已分配磁盘的方法 第一步&#xff1a;用VirtualBox命令行调整已分配磁盘的大小第二步&#xff1a;用windows磁盘管理工具扩展磁盘空间其他无关配置如何选择虚拟机的芯片组 注意&#xff1a;扩展操作只支持 vdi 格式的磁盘&#xff0c;就是VirtualBox自己的磁盘…...

【LeetCode】646. 最长数对链

646. 最长数对链&#xff08;中等&#xff09; 思路 这道题和 300. 最长递增子序列 类似&#xff0c;我们可以定义 dp 数组&#xff0c;其中 dp[i] 表示以 i 结尾的子序列的性质。在处理好每个位置后&#xff0c;统计一遍各个位置的结果即可得到题目要求的结果。 但是题目中强…...

Makefile教程(Makefile的结构)

文章目录 前言一、Makefile的结构二、深入案例三、Makefile中的一些技巧总结 前言 一、Makefile的结构 Makefile 通常由一系列规则组成&#xff0c;每条规则定义了如何从源文件生成目标文件。每个规则又由目标、依赖和命令三部分组成。 下面是 Makefile 规则的基本结构&…...

优跃达官网网站建设项目/爱站网排行榜

3-1、标识符。为什么python 中不需要变量名和变量类型声明&#xff1f; python语言是动态的、强类型语言&#xff0c;一言以蔽之&#xff01; 动态编译语言特点&#xff1a;  ◆不用事先声明类型&#xff0c;随时赋值为其他类型  ◆编译时不知道是什么类型&#xff0c;很难…...

大连金州代做网站公众号/快速排名教程

马哲包括5大部分即唯物论&#xff0c;辩证法&#xff0c;认识论&#xff0c;历史唯物论&#xff0c;资本主义本质论。 其中辩证法又包括&#xff1a; 1.两大特征&#xff1a;&#xff08;1&#xff09;普遍联系&#xff08;2&#xff09;永恒发展。 2.三大规律&#xff1a;&…...

手机网站格式商城/互联网营销师报名入口

copy.deepcopy()的用法是将某一个变量的值赋值给另一个变量(此时两个变量地址不同)&#xff0c;因为地址不同&#xff0c;所以可以防止变量间相互干扰。大家可以猜猜下面代码第四行输出什么值例1.a [1, 2, 3]d a # a和d的地址相同&#xff0c; 看第5行的输出a[0] 2print(d)p…...

零售户电商网站订货网址/美业推广平台

它发生在我们所有人身上 —— 生活变得忙碌&#xff0c;我们与朋友失去联系。偶尔的电话和短信只够勉强了解他们的生活和家庭。 我们求助于通过社交媒体来跟随他们&#xff0c;在这里我们看到他们渡过美好假期、搬到新房子或换了工作。即使您无法参加聚会&#xff0c;你也能看到…...

自己做qq代刷网站要钱吗/自媒体怎么做

大家好,我是小马老师。 本文介绍python统计并输出CNA结构分析结果。 Ovito CNA模块可以分析不同时刻的晶体结构,但是在ovito软件中的分析结果不方便直接绘图输出,因此本文给出一个python脚本,运行之后可以直接绘制不同晶体结构的比例图。 程序使用方法: 复制以下pyth…...

com域名代表什么/提高seo关键词排名

据麦姆斯咨询报道&#xff0c;东芝已成功研发出具有3D识别功能的单目摄像头人工智能(AI)技术&#xff0c;测量距离的精度不输立体摄像头。东芝的方案采用市售单目摄像头拍摄图像&#xff0c;然后利用独特设计的镜头造成图像模糊&#xff0c;通过深度学习分析来实现。该技术降低…...