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

Linux高级编程——线程

pthread 线程
   

    概念 :线程是轻量级进程,一般是一个进程中的多个任务
                进程是系统中最小的资源分配单位.
                线程是系统中最小的执行单位。

  优点: 比多进程节省资源,可以共享变量

进程会占用3g左右的空间,线程只会占用一部分,大概8M的空间

进程的父子不会共享,但一个进程之间的线程的资源可以共享.

进程的父子不是平级关系,线程是平级关系

 特征:s's
    1、共享资源
    2、效率高  30%
    3、三方库: pthread  clone   posix
            3.1 编写代码头文件: pthread.h
            3.2 编译代码加载库: -lpthread   library 
            libpthread.so  (linux库)
            gcc 1.c -lpthread     -lc
    缺点:
    1,线程和进程相比,稳定性,稍微差些
    2,线程的调试gdb,相对麻烦些。
        info thread 
        *1  
        2 
        3
        thread 3 
        
线程与进程区别:

    资源:
        线程比进程多了共享资源。  IPC
        线程又具有部分私有资源。
        进程间只有私有资源没有共享资源。
    空间:
        进程空间独立,不能直接通信。
        线程可以共享空间,可以直接通信。

       进程解决相对复杂的问题,线 程解决相对复杂的问题.

共同点:

二者都可以并发

3、线程的设计框架  posix
    

创建多线程 ==》线程空间操作 ===》线程资源回收
errno   strerror(errno)  perror();
  

 3.1 创建多线程:


    int pthread_create(
        pthread_t *thread const pthread_attr_t *attr,
        void *(*start_routine) (void *), void *arg);
    功能:该函数可以创建指定的一个线程。
    参数:thread 线程id,需要实现定义并由该函数返回。
          attr   线程属性,一般是NULL,表示默认属性。
          start_routine      指向指针函数的函数指针。
                  本质上是一个函数的名称即可。称为
th                回调函数,是线程的执行空间。
{
}
          arg  回调函数的参数,即参数3的指针函数参数。
 

 返回值:成功 0
                失败 错误码

注意:一次pthread_create执行只能创建一个线程。
      每个进程至少有一个线程称为主线程。
      主线程退出则所有创建的子线程都退出。暂时先用while(1); 
      主线程必须有子线程同时运行才算多线程程序。
      线程id是线程的唯一标识,是CPU维护的一组数字。
      pstree 查看系统中多线程的对应关系。
      多个子线程可以执行同一回调函数。
    ps -eLf 查看线程相关信息Low Weigth Process
    ps -eLo pid,ppid,lwp,stat,comm

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
void *th1(void*arg)
{while(1){printf("发送视频\n");sleep(1);}
}void *th2(void*arg)
{while(1){printf("接受控制\n");}
}int main(int argc, const char *argv[])
{pthread_t tid1,tid2;pthread_create(&tid1,NULL,th1,NULL);pthread_create(&tid2,NULL,th2,NULL);while(1);return 0;
}
  1. main 函数开始执行。
  2. 使用 pthread_create 创建了两个线程 tid1 和 tid2
  3. th1 线程开始执行其无限循环,并在每次迭代中打印 "发送视频",然后暂停一秒。
  4. 同时(几乎是同时),th2 线程也开始执行其无限循环,不断打印 "接受控制"。
  5. 因为两个线程是并发执行的,所以它们之间没有固定的打印顺序。这取决于操作系统调度器的决策,哪个线程在何时获得CPU时间片。
  6. main 函数中的 while(1); 是一个空循环,它使主线程保持活动状态,防止程序立即退出。然而,这个空循环并没有为程序提供任何有用的功能,通常你可能会使用某种形式的线程同步或等待(如 pthread_join)来确保主线程在所有其他线程完成后才退出。

此时输出是乱的,是由于

  • 线程调度是由操作系统控制的,它决定哪个线程在何时运行。这取决于许多因素,包括线程优先级、系统负载、可用的CPU核心数量等。
  • 由于两个线程都在无限循环中,并且没有同步机制(如互斥锁、条件变量等),所以它们会尽可能快地交替执行(或并行执行,如果系统有多个CPU核心),导致输出看起来没有规律。

2、pthread_t pthread_self(void); unsigned long int; %lu  获取线程号


   功能:获取当前线程的线程id
   参数:无
   返回值:成功 返回当前线程的线程id
               失败  -1;
            syscall(SYS_gettid);
这个方法重启后失效
alias gcc='gcc -g -pthread '
unalias gcc 

永久起作用
cd ~ //家目录
vim .bashrc
alias gcc='gcc -g -pthread '  :wq

source .bashrc  生效

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
void *th1 (void*arg)
{while(1){printf("发送视频 %lu\n",pthread_self());sleep(1);}
}void *th2 (void*arg)
{while(1){printf("接受控制 %lu\n",pthread_self());sleep(1);}
}int main(int argc, char *argv[])
{pthread_t tid1,tid2;pthread_create(&tid1,NULL,th1,NULL);pthread_create(&tid2,NULL,th2,NULL);printf("main th %lu\n",pthread_self());while(1);return 0;
}
  • 使用pthread_create创建两个线程:tid1(运行th1)和tid2(运行th2)。
  • 打印主线程的ID。
  • 使用while(1);使主线程进入无限循环,以保持程序运行。否则,当主线程结束时,程序可能会立即终止,导致其他线程也被终止

练习题:
    设计一个多线程程序,至少有三个子线程
    每个线程执行不同的任务,并实时打印执行
    过程,同时表明身份。

    eg: ./a.out  ==>tid =xxx...  zheng ...
                    tid2 = xxx wozai.
                    tid3 = xxx  wozai ssss


线程的退出:

1.直接用return;   

2: 自行退出 ==》自杀  ==》子线程自己退出
        exit(1);
        void pthread_exit(void *retval);  exit  return p;
        功能:子线程自行退出
        参数: retval 线程退出时候的返回状态,临死遗言。
        返回值:无

            th
            {
                int a =10;

                pthread_exit(&a);
            }
            join(,&ret)


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
void *th1 (void*arg)
{int i =10;while(i--){printf("发送视频 %lu\n",pthread_self());sleep(1);}pthread_exit(NULL);//return NULL;
}void *th2 (void*arg)
{int i = 10;while(i--){printf("接受控制 %lu\n",pthread_self());sleep(1);}pthread_exit(NULL);
}int main(int argc, char *argv[])
{pthread_t tid1,tid2;pthread_create(&tid1,NULL,th1,NULL);pthread_create(&tid2,NULL,th2,NULL);printf("main th %lu\n",pthread_self());while(1);return 0;
}


    3. 强制退出 ==》他杀  ==》主线程结束子线程
        int pthread_cancel(pthread_t thread);
        功能:请求结束一个线程  (在主线程种调用 写入某个线程id号,可以关闭该线程)
        参数:thread 请求结束一个线程tid(想要关闭的线程id号)
        返回值:成功 0
                失败 -1;

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
void *th1 (void*arg)
{while(1){printf("发送视频\n");sleep(1);}
}void *th2 (void*arg)
{while(1){printf("接受控制\n");sleep(1);}
}int main(int argc, char *argv[])
{pthread_t tid1,tid2;pthread_create(&tid1,NULL,th1,NULL);pthread_create(&tid2,NULL,th2,NULL);int i = 0 ;while(1){i++;if(3 == i ){pthread_cancel(tid1);}if(5 ==i){pthread_cancel(tid2);}sleep(1);}return 0;
}

作业:
    创建一个多线程程序,至少有10个子线程,
    每个线程有会打印不同的数据,同时表明身份。

    
    线程的回收


    1、线程的回收机制 ====》不同与进程没有孤儿线程和僵尸线程。
                                    ====》主线程结束任意生成的子线程都会结束。
                                      ====》 子线程的结束不会影响主线程的运行。
    char * retval ; retval++; 1 
    int * retval; 

    int pthread_join(pthread_t thread, void **retval);    
  功能:通过该函数可以将指定的线程资源回收,该函数具有阻塞等待功能,如果指定的线程没有结束,则回收线程会阻塞。
  参数:thread  要回收的子线程tid
              retval  要回收的子线程返回值/状态。==》ptread_exit(值);
  返回值:成功 0
                 失败 返回一个错误号,是一个大于零的数;

                  失败可以用

               

 

#include <unistd.h>
#include <string.h>
#include <pthread.h>
void *th1 (void*arg)
{int i = 10;while(i--){printf("发送视频\n");sleep(1);}
}void *th2 (void*arg)
{int i = 10;while(i--){printf("接受控制\n");sleep(1);}
}int main(int argc, char *argv[])
{pthread_t tid1,tid2;pthread_create(&tid1,NULL,th1,NULL);int ret = pthread_create(&tid2,NULL,th2,NULL);if(ret!=0){// perror()fprintf(stderr,"error %s\n",strerror(ret));//exit();}pthread_join(tid1,NULL);pthread_join(tid2,NULL);return 0;
}

子线程的回收策略:
  1、如果预估子线程可以有限范围内结束则正常用pthread_join等待回收。
  2、如果预估子线程可能休眠或者阻塞则等待一定时间后强制回收。
  3、如果子线程已知必须长时间运行则,不再回收其资源。
  
  


  线程的参数,返回值
  

1、传参数
        
    传整数 ===》int add(int a,int b);  ///a b 形参
                add(x,y);    x y 实参 

        pthread_create(&tid,NULL,fun,x);

        fun ==>void * fun(void * arg);
        
    练习:创建一个子线程并向该线程中传入一个字符在
          线程中打印输出。
          在此基础上向子线程中传入一个字符串,并在
          子线程中打印输出。

          
          add(int a, int b)
          {
            int c = a+b;
            char buf[]=""
            return c;
          }
                    5
          int d = add(2,3);

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>void* th(void* arg)
{static int a =20;return &a;
}int main(int argc, char *argv[])
{pthread_t tid;void* ret;pthread_create(&tid,NULL,th,NULL);pthread_join(tid,&ret);printf("ret %d\n",*(int*)ret);return 0;
}


    传字符串
        栈区字符数组:
        字符串常量:
        char *p = "hello";
        堆区字符串;
            char *pc = (char *)malloc(128);
            ptread_create(&tid,NULL,fun,pc);

            pthread_join(tid,NULL);

            free(pc);
        
            fun(void *arg)
            {
                char * pc = (char *)arg    ;
                printf("%s \n",pc);
                        %c
            }

栈区

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>void* th(void* arg)
{static char buf[256]={0};strcpy(buf,"要消亡了\n");return buf;
}int main(int argc, char *argv[])
{pthread_t tid;void* ret;pthread_create(&tid,NULL,th,NULL);pthread_join(tid,&ret);printf("ret %s\n",(char*)ret);return 0;
}

堆区:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>void* th(void* arg)
{char * tmp = (char* )arg;strcpy(tmp,"hello");return tmp;
}int main(int argc, char *argv[])
{pthread_t tid;char * p = (char*)malloc(50);void* ret;pthread_create(&tid,NULL,th,p);pthread_join(tid,&ret);printf("ret %s\n",(char*)ret);free(p);return 0;
}

  

 传结构体
    1、定义结构体类型
    2、用结构体定义变量
    3、向pthread_create传结构体变量
    4、从fun子线程中获取结构体数据

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
typedef struct 
{char * p;int a;
}TH_ARG;
void* th(void* arg)
{TH_ARG * tmp = (TH_ARG* )arg;strcpy(tmp->p,"hello");//strcpy( ((TH_ARG*)arg)->p ,"hello");tmp->a +=10;return tmp;
}int main(int argc, char *argv[])
{pthread_t tid;int a  =20;char * p = (char*)malloc(50);TH_ARG arg;arg.a = a;arg.p = p;void* ret;pthread_create(&tid,NULL,th,&arg);pthread_join(tid,&ret);printf("ret %s %d\n",((TH_ARG*)ret)->p,((TH_ARG*)ret)->a);free(p);return 0;
}

练习:
    定义一个包含不同数据类型的测试结构体
    并向子线程传参数,同时在子线程中打印输出。


    定义一个回调函数可以完成计算器的功能
    定义一个数据结构体可以一次传入不同的数据
    和计算方式并将结果打印输出。
    //2 + 3.6 
    // 2 + 3  2+3
    // 8 * 6
    typedef strcut
    {
        float a;
        float b;
        char c;//+ - * / 
        float d;
    }JSQ;
    
    

返回值:pthread_exit(0) ===>pthread_exit(9);
        pthread_join(tid,NULL); ===>pthread_join(tid,?);
10;
-10;
int * p =malloc(4);
*p = -10;
1、pthread_exit(?) ==>? = void * retval;
                          纯地址

2、pthread_join(tid,?) ==>? = void **retval;
                            地址的地址
原理:子线程退出的时候,可以返回一个内存地址
      改值所在的内存中可以存储任何数据,只要
      地址存在,则数据都可以正常返回。
    
    地址有三种:
    0、栈区变量  错误,子线程结束该地址失效。
    1、全局变量  失去意义,本质可以直接访问。

    2、静态变量 
    3、堆区变量


      主线程通过一个地址形式的变量来接受子进程
      返回的地址变量就可以将该地址中的数据取到。

    练习:从子线程中申请一块堆区内存并存字符串
      将该字符串以返回值形式返回到主线程并打印输出。
          
 

   设置分离属性,目的线程消亡,自动回收空间。
  

主线程没有空,才设置分离属性来回收.

 attribute

 int pthread_attr_init(pthread_attr_t *attr);
    功能,初始化一个attr的变量
    参数:attr,需要变量来接受初始值
    返回:0  成功,
    非0 错误;
       int pthread_attr_destroy(pthread_attr_t *attr);
      功能:销毁attr变量。
      attr,属性变量
      返回:0  成功,
    非0 错误;
       
       
    man -k 
     int pthread_attr_setdetachstate(pthread_attr_t *attr
, int detachstate);

    功能:把一个线程设置成相应的属性
    参数,attr,属性变量,有init函数初始化他。
    detachstate:有2个可选值,
    
    PTHREAD_CREATE_DETACHED:设置分离属性。
    
    第二种设置分离属性:
int pthread_deatch(pthread_t thread);
    功能,设置分离属性
    参数,线程id号,填自己的id
    
    do{
    
    
    }while()

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void* th(void* arg)
{pthread_detach(pthread_self());return NULL;
}int main(int argc, char *argv[])
{pthread_t tid;int i = 0 ;for(i=0;i<50000;i++){int ret = pthread_create(&tid,NULL,th,NULL);if(ret!=0){break;}// pthread_detach(tid);}printf("%d \n",i);return 0;
}


void pthread_cleanup_push(void (*routine)(void *), void *arg);

    功能:注册一个线程清理函数
    参数,routine,线程清理函数的入口
        arg,清理函数的参数。
    返回值,无
        
void pthread_cleanup_pop(int execute);
    功能:调用清理函数
    execute,非0  执行清理函数
            0 ,不执行清理
            
    返回值,无

do
{

}while(1)

process                thread
fork                pthread_create 
getpid,ppid,        pthread_self
exit,                pthread_exit 
wait,waitpid,        pthread_join 
kill,                pthread_cancel
atexit                 pthread_clean,
exec                system--->fork->exec (ls)
                    
 

相关文章:

Linux高级编程——线程

pthread 线程 概念 &#xff1a;线程是轻量级进程&#xff0c;一般是一个进程中的多个任务。 进程是系统中最小的资源分配单位. 线程是系统中最小的执行单位。 优点&#xff1a; 比多进程节省资源&#xff0c;可以共享变量 进程会占用&am…...

技术学习的奥秘与乐趣

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 在当今快速发展的科技时代&#xff0c;学习技术已经成为了许多人追求的重要目标之一。无论是为了个人发展&#…...

创新前沿:Web3如何颠覆传统计算机模式

随着Web3技术的快速发展&#xff0c;传统的计算机模式正面临着前所未有的挑战和改变。本文将深入探讨Web3技术的定义、原理以及它如何颠覆传统计算机模式&#xff0c;以及对全球科技发展的潜在影响。 1. 引言&#xff1a;Web3技术的兴起与背景 Web3不仅仅是技术创新的一种&…...

一文弄懂梯度下降算法

1、引言 在上一篇文章中&#xff0c;我们介绍了如何使用线性回归和成本损失函数为房价数据找到最拟合的线。不过&#xff0c;我们也看到&#xff0c;测试多个截距值可能既繁琐又低效。在本文中&#xff0c;我们将深入探讨梯度下降算法&#xff0c;这是一种更加强大的技术&…...

确认偏差:金融市场交易中的隐形障碍

确认偏差&#xff0c;作为一种深刻影响交易员决策与表现的心理现象&#xff0c;其核心在于个体倾向于寻求与既有信念相符的信息&#xff0c;而自动过滤或轻视与之相悖的资讯。这种认知偏见严重扭曲了交易者的决策过程&#xff0c;导致他们过分依赖符合既有观念的数据&#xff0…...

Linux系统之部署linkding书签管理器

Linux系统之部署linkding书签管理器 一、linkding介绍1.1 linkding简介1.2 linkding特点二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本四、部署Node.js 环境4.1 下载Node.js安装包4.2 解压Node.js安装包4.3 …...

springcloud-gateway 路由加载流程

问题 Spring Cloud Gateway版本是2.2.9.RELEASE&#xff0c;原本项目中依赖服务自动发现来自动配置路由到微服务的&#xff0c;但是发现将spring.cloud.gateway.discovery.locator.enabledfalse 启动之后Gateway依然会将所有微服务自动注册到路由中&#xff0c;百思不得其解&a…...

双减期末考试成绩怎么公布?

考试一直是衡量学生学习成果的重要手段。不过&#xff0c;随着"双减"政策的实施&#xff0c;我们就不得不重新审视传统的成绩公布方式。期末考试成绩&#xff0c;这个曾经让无数学生心跳加速的数字&#xff0c;如今该如何以一种更加合理、公正的方式呈现给学生和家长…...

2, 搭建springCloud 项目 测试demo

上篇文章 新建了父依赖服务&#xff0c;这篇文章就建两个demo测试服务。 因为后面需要做服务间的通讯测试&#xff0c;所以至少需要建两个服务 建个子模块 同样的方式建连个demo服务 给java 和resources目录添加属性 在resources目录下建一个applications.yml文件&#xff0c;…...

RabbitMQ消息积压比较厉害,然后突然丢弃

RabbitMQ中的消息积压陡降通常表明某些突发事件或操作已经显著减少了队列中的消息数量。这种现象可能由多种原因引起&#xff0c;以下是一些可能的原因及其解释&#xff1a; 消费者处理速度突然增加 原因: 你的消费者&#xff08;消费者应用或服务&#xff09;可能在某个时间点…...

QT中的样式表.qss文件

一、前言 qt中样式表的改变有几种方法&#xff0c;第一种就是直接在ui界面对应的组件右键修改样式表&#xff0c;还有一种就是直接在程序里面修改样式表&#xff0c;我知道的还有一种就是qss文件&#xff0c;这个文件就是将在程序中写的修改样式表的语句写道qss文件中&#xff…...

HTML图片链接缓存问题解决

关于解决HTML使用图片链接出现的缓存问题处理 1、项目上明明替换了图片却没发现更新&#xff0c;得去浏览器设置清除浏览器缓存或者其它一些操作才能解决&#xff0c;这也太麻烦了&#xff01;加载过一次不会再加载第二次&#xff0c;其实这时候就存在浏览器图片缓存情况&…...

一个人 三个月 干了二十万

相信很多人是被这个标题吸引进来的&#xff0c;但我并不是标题党&#xff0c;我也很讨厌标题党&#xff0c;这篇文章也不在乎流量&#xff0c;更多的是想记录下。 出来创业三个多月了&#xff0c;给大家汇报一下这段时间的业绩吧。一个人&#xff0c;三个多月&#xff0c;干了…...

设计模式之【工厂模式、适配器模式】

工厂模式&#xff08;Factory Pattern&#xff09; 定义&#xff1a; 工厂模式是一种创建型设计模式&#xff0c;它提供了一个创建对象的接口&#xff0c;但由子类决定要实例化的类是哪一个。工厂方法使一个类的实例化延迟到其子类。 主要类型&#xff1a; 简单工厂模式&…...

云计算:重塑数字时代的基石

目录 一、引言 二、云计算的定义与特点 三、云计算的发展历程 四、云计算的应用场景 五、云计算面临的挑战 六、云计算的未来发展趋势 七、结语 一、引言 随着信息技术的飞速发展&#xff0c;云计算已经逐渐渗透到我们生活的方方面面。从个人用户的在线存储、在线办公&…...

C# SocketUDP服务器,组播

SocketUDP 自己即是服务器又是客户端 &#xff0c;在发消息只需要改成对方ip和端口号即可 前提对方必须开启服务器 socket.Bind(new IPEndPoint(IPAddress.Parse("192.168.107.72"), 8080)); 控件&#xff1a;Button,TextBox,RichTextBox 打开自己服务器 public…...

上市公司绿色投资者原始数据+计算代码(2008-2022年)

数据简介&#xff1a;“绿色”信号&#xff0c;意味着潜在环境风险更低&#xff0c;从而绿色投资者降低了对绿色债券的风险补偿要求&#xff0c;推动了信用利差的收窄。因此&#xff0c;绿色投资者会通过投资者风险意识影响债券信用风险。绿色投资者在推动企业绿色可持续发展方…...

Redis-主从复制-测试主从模式下的读写操作

文章目录 1、在主机6379写入数据2、在从机6380上写数据报错3、从机只能读数据&#xff0c;不能写数据 1、在主机6379写入数据 127.0.0.1:6379> keys * (empty array) 127.0.0.1:6379> set uname jim OK 127.0.0.1:6379> get uname "jim" 127.0.0.1:6379>…...

Linux系统应用与设置(3):串口调试(minicom)

目录 1. 简述 2. 安装minicom 3. 配置串口参数 4. 打开相应的通信端口 5. 设置 6. 发送字符数据 7. 发送HEX&#xff08;十六进制&#xff09; 1. 简述 在Linux系统中&#xff0c;minicom是一个功能强大的串口通信工具&#xff0c;可用于与外部设备进行字符和HEX数据的收…...

Qt | windows Qt6.5.3安卓环境搭建成功版(保姆级教程)

01、第一章 Qt6.5.3安装 资源 Qt 国内下载地址清华大学开源软件镜像站https://mirrors.tuna.tsinghua.edu.cn/qt/archive/online_installers/Qt 阿里云盘下载Qt 安卓开发https://www.alipan.com/s/kNaues6CHaG点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式

今天是关于AI如何在教学中增强学生的学习体验&#xff0c;我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育&#xff0c;这并非炒作&#xff0c;而是已经发生的巨大变革。教育机构和教育者不能忽视它&#xff0c;试图简单地禁止学生使…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...