[线程/C]基础

news2024/11/14 18:30:53

文章目录

  • 1. 线程介绍
  • 2. 创建线程
    • 2.1 线程函数
    • 2.2 创建线程
  • 3. 线程退出
  • 4. 线程回收
    • 4.1 线程函数
    • 4.2 回收子线程数据
      • 4.2.1 使用子线程栈
      • 4.2.2 使用全局变量
      • 4.2.3 使用主线程栈
  • 5. 线程分离
  • 6. 其他线程函数
    • 6.1 线程取消
    • 6.2 线程ID的比较


1. 线程介绍

线程是轻量级的进程(LWP:light weight process),在Linux环境下线程的本质仍是进程。
在计算机上运行的程序是一组指令及指令参数的组合,指令按照既定的逻辑控制计算机运行。
操作系统会以进程为单位,分配系统资源,可以这样理解
进程是资源分配的最小单位,线程是操作系统调度执行的最小单位。

从概念上来说线程和进程的区别:

  • 进程有自己独立的地址空间, 多个线程共用同一个地址空间

    • 线程更节省系统资源, 效率不仅可以保持, 而且能更高
    • 在一个地址空间中多个线程独享: 每个线程都有属于自己的栈区, 寄存器(内核中管理的)
    • 在一个地址空间中多个线程共享: 代码段, 堆区, 全局数据区, 打开的文件(文件描述符表)
  • 线程是程序的最小执行单位, 进程是操作系统中最小的资源分配单位

    • 每个进程对应一个虚拟地址空间,一个进程只能抢一个CPU时间片
    • 一个地址空间中可以划分出多个线程, 能在有效的资源基础上, 抢更多的CPU时间片

在这里插入图片描述

  • CPU的调度和切换: 线程的上下文切换比进程要快的多
    上下文切换:进程/线程分时复用CPU时间片,在切换之前会将上一个任务的状态进行保存, 下次切换回这个任务的时候, 加载这个状态继续运行,任务从保存到再次加载这个过程就是一次上下文切换。
  • 线程更加廉价, 启动速度更快, 退出也快, 对系统资源的冲击小。

在处理多任务程序的时候使用多线程比使用多进程要更有优势,但是线程并不是越多越好

  1. 文件IO操作:文件IO对CPU是使用率不高, 因此可以分时复用CPU时间片
    线程的个数 = 2 * CPU核心数 (效率最高)
  2. 处理复杂的算法(主要是CPU进行运算, 压力大)
    线程的个数 = CPU的核心数 (效率最高)

2. 创建线程

2.1 线程函数

每一个线程都有一个唯一的线程ID,ID类型为pthread_t
这个ID是一个无符号长整形(unsigned long)

如果想要得到当前线程的线程ID,可以调用如下函数:

pthread_t pthread_self(void);	// 返回当前线程的线程ID

在一个进程中调用线程创建函数,就可得到一个子线程
和进程不同,需要给每一个创建出的线程指定一个处理函数,否则这个线程无法工作。

#include <pthread.h>
int pthread_create(pthread_t *thread,
 					const pthread_attr_t *attr,
                    void *(*start_routine) (void *), 
                    void *arg);
// Compile and link with -pthread
//线程库的名字叫pthread, 全名: libpthread.so libptread.a

介绍一下pthread_create函数的

  • 参数
    thread: 传出参数,无符号长整形,线程创建成功, 会将线程ID写入到这个指针指向的内存中
    attr: 线程的属性, 一般情况下使用默认属性即可, 写NULL
    start_routine: 函数指针,创建出的子线程的处理动作,该函数在子线程中执行。
    arg: 作为实参传递到 start_routine 指针指向的函数内部
  • 返回值:线程创建成功返回0,创建失败返回对应的错误号

2.2 创建线程

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>    

 子线程的处理代码
void* Work(void* args)
{
	printf("子线程id: %ld\n",pthread_self());
    for(int i = 0; i < 5 ; ++i)
    {
        printf("child == i : %d\n",i);
     }
    return NULL;
}
int main()
{
    //1.创建子线程
    pthread_t tid;
    pthread_create(&tid,NULL,Work,NULL);

    printf("子线程创建成功,线程id : %ld\n",tid);
    
    //2.子线程不会执行下面的代码,由主线程执行
    printf("主线程id : %ld\n", pthread_self());
    for(int i = 0; i < 3 ; ++i)
    {
        printf("i == %d\n",i);
    }
    //进行休息,否则可能导致子线程未执行时,主线程已经结束,直接结束了进程
    sleep(1);
    return 0;
}

使用gcc编译时容易出现的错误

gcc pthread_create.c 

错误原因是编译器链接不到线程库文件(动态库),需在编译时通过参数指定出来
动态库名为 libpthread.so需要使用的参数为 -l
据规则掐头去尾最终形态应该写成:-lpthread(参数和参数值中间可以有空格)。

所以正确的写法是

 gcc pthread_create.c -lpthread

在打印的输出中为什么子线程处理函数没有执行呢(只看到了子线程的部分日志输出?
主线程一直在运行, 执行期间创建出了子线程,说明主线程有CPU时间片, 在这个时间片内将代码执行完毕了, 主线程就退出了。
子线程被创建出来之后需要抢cpu时间片, 抢不到就不能运行,如果主线程退出了, 虚拟地址空间就被释放了, 子线程一并销毁
但是如果某一个子线程退出了, 主线程仍在运行, 虚拟地址空间依旧存在。
结论:在没有人为干预的情况下,虚拟地址空间的生命周期和主线程是一样的,与子线程无关。
目前的解决方案: 让子线程执行完毕, 主线程再退出, 可以在主线程中添加挂起函数 sleep();


3. 线程退出

在编写多线程程序的时候,如果想要让线程退出,但不导致虚拟地址空间的释放(针对于主线程)
我们就可以调用线程库中的线程退出函数,只要调用该函数当前线程就马上退出了,并且不会影响到其他线程的正常运行,不管是在子线程或者主线程中都可以使用

#include <pthread.h>
void pthread_exit(void *retval);
  • 参数:
    线程退出时携带的数据,当前子线程的主线程会得到该数据。如果不需要使用,指定为NULL

eg:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

// 子线程的处理代码
void* working(void* arg)
{
    sleep(1);
    printf("我是子线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<9; ++i)
    {
        if(i==6)
        {
            pthread_exit(NULL);	// 直接退出子线程
        } 
        printf("child == i: = %d\n", i);
    }
    return NULL;
}

int main()
{
    // 1. 创建一个子线程
    pthread_t tid;
    pthread_create(&tid, NULL, working, NULL);

    printf("子线程创建成功, 线程ID: %ld\n", tid);
    // 2. 子线程不会执行下边的代码, 主线程执行
    printf("我是主线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<3; ++i)
    {
        printf("i = %d\n", i);
    }

    // 主线程调用退出函数退出, 地址空间不会被释放
    pthread_exit(NULL);
    
    return 0;
}

4. 线程回收

4.1 线程函数

线程和进程一样,子线程退出的时候其内核资源主要由主线程回收
线程库中提供的线程回收函叫做pthread_join()
这个函数是一个阻塞函数
子线程在运行, 调用该函数就会阻塞
子线程退出, 函数解除阻塞进行资源的回收.
函数被调用一次,只能回收一个子线程,如果有多个子线程则需要循环进行回收。
另外通过线程回收函数还可以获取到子线程退出时传递出来的数据,函数原型如下:

#include <pthread.h>
// 这是一个阻塞函数, 子线程在运行这个函数就阻塞
// 子线程退出, 函数解除阻塞, 回收对应的子线程资源, 类似于回收进程使用的函数 wait()
int pthread_join(pthread_t thread, void **retval);
  • 参数:
    • thread: 要被回收的子线程的线程ID
    • retval: 二级指针, 指向一级指针的地址, 是一个传出参数, 这个地址中存储了pthread_exit() 传递出的数据,如果不需要这个参数,可以指定为NULL
  • 返回值:线程回收成功返回0,回收失败返回错误号。

4.2 回收子线程数据

在子线程退出的时候可以使用pthread_exit()的参数将数据传出
在回收这个子线程的时候可以通过phread_join()的第二个参数来接收子线程传递出的数据。接收数据有很多种处理方式,列举几种:

4.2.1 使用子线程栈

通过函数pthread_exit(void *retval);可以得知,子线程退出的时候,需要将数据记录到一块内存中,通过参数传出的是存储数据的内存的地址,而不是具体数据,因为参数是void*类型,所有这个万能指针可以指向任意类型的内存地址。先来看第一种方式,将子线程退出数据保存在子线程自己的栈区:

// pthread_join.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

// 定义结构
struct Persion
{
    int id;
    char name[36];
    int age;
};

// 子线程的处理代码
void* working(void* arg)
{
    printf("我是子线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<9; ++i)
    {
        printf("child == i: = %d\n", i);
        if(i == 6)
        {
            struct Persion p;
            p.age  =12;
            strcpy(p.name, "tom");
            p.id = 100;
            // 该函数的参数将这个地址传递给了主线程的pthread_join()
            pthread_exit(&p);
        }
    }
    return NULL;	// 代码执行不到这个位置就退出了
}

int main()
{
    // 1. 创建一个子线程
    pthread_t tid;
    pthread_create(&tid, NULL, working, NULL);

    printf("子线程创建成功, 线程ID: %ld\n", tid);
    // 2. 子线程不会执行下边的代码, 主线程执行
    printf("我是主线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<3; ++i)
    {
        printf("i = %d\n", i);
    }

    // 阻塞等待子线程退出
    void* ptr = NULL;
    // ptr是一个传出参数, 在函数内部让这个指针指向一块有效内存
    // 这个内存地址就是pthread_exit() 参数指向的内存
    pthread_join(tid, &ptr);
    // 打印信息
    struct Persion* pp = (struct Persion*)ptr;
    printf("子线程返回数据: name: %s, age: %d, id: %d\n", pp->name, pp->age, pp->id);
    printf("子线程资源被成功回收...\n");
    
    return 0;
}

但是当我们编译时打印出的信息并没有得到子线程的数据

具体原因是这样的:
如果多个线程共用同一个虚拟地址空间,每个线程在栈区都有一块属于自己的内存,相当于栈区被这几个线程平分了,当线程退出,线程在栈区的内存也就被回收了,因此随着子线程的退出,写入到栈区的数据也就被释放了。


4.2.2 使用全局变量

位于同一虚拟地址空间中的线程,虽然不能共享栈区数据,但可以共享全局数据区和堆区数据,因此在子线程退出的时候可以将传出数据存储到全局变量、静态变量或者堆内存中。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

// 定义结构
struct Persion
{
    int id;
    char name[36];
    int age;
};

struct Persion p;	// 定义全局变量

// 子线程的处理代码
void* working(void* arg)
{
    printf("我是子线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<9; ++i)
    {
        printf("child == i: = %d\n", i);
        if(i == 6)
        {
            // 使用全局变量
            p.age  =12;
            strcpy(p.name, "tom");
            p.id = 100;
            // 该函数的参数将这个地址传递给了主线程的pthread_join()
            pthread_exit(&p);
        }
    }
    return NULL;
}

int main()
{
    // 1. 创建一个子线程
    pthread_t tid;
    pthread_create(&tid, NULL, working, NULL);

    printf("子线程创建成功, 线程ID: %ld\n", tid);
    // 2. 子线程不会执行下边的代码, 主线程执行
    printf("我是主线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<3; ++i)
    {
        printf("i = %d\n", i);
    }

    // 阻塞等待子线程退出
    void* ptr = NULL;
    // ptr是一个传出参数, 在函数内部让这个指针指向一块有效内存
    // 这个内存地址就是pthread_exit() 参数指向的内存
    pthread_join(tid, &ptr);
    // 打印信息
    struct Persion* pp = (struct Persion*)ptr;
    printf("name: %s, age: %d, id: %d\n", pp->name, pp->age, pp->id);
    printf("子线程资源被成功回收...\n");
    
    return 0;
}

4.2.3 使用主线程栈

虽然每个线程都有属于自己的栈区空间,但是位于同一个地址空间的多个线程是可以相互访问对方的栈空间上的数据的。
由于很多情况下还需要在主线程中回收子线程资源,所以主线程一般都是最后退出,基于这个原因在下面程序中将子线程返回的数据保存到了主线程的栈区内存中:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

// 定义结构
struct Persion
{
    int id;
    char name[36];
    int age;
};


// 子线程的处理代码
void* working(void* arg)
{
    struct Persion* p = (struct Persion*)arg;
    printf("我是子线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<9; ++i)
    {
        printf("child == i: = %d\n", i);
        if(i == 6)
        {
            // 使用主线程的栈内存
            p->age  =12;
            strcpy(p->name, "tom");
            p->id = 100;
            // 该函数的参数将这个地址传递给了主线程的pthread_join()
            pthread_exit(p); //p本来就是指针
        }
    }
    return NULL;
}

int main()
{
    // 1. 创建一个子线程
    pthread_t tid;

    struct Persion p;
    // 主线程的栈内存传递给子线程
    pthread_create(&tid, NULL, working, &p);

    printf("子线程创建成功, 线程ID: %ld\n", tid);
    // 2. 子线程不会执行下边的代码, 主线程执行
    printf("我是主线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<3; ++i)
    {
        printf("i = %d\n", i);
    }

    // 阻塞等待子线程退出
    void* ptr = NULL;
    // ptr是一个传出参数, 在函数内部让这个指针指向一块有效内存
    // 这个内存地址就是pthread_exit() 参数指向的内存
    pthread_join(tid, &ptr);
    // 打印信息
    printf("name: %s, age: %d, id: %d\n", p.name, p.age, p.id);
    printf("子线程资源被成功回收...\n");
    
    return 0;
}

在上面的程序中,调用pthread_create()创建子线程,并将主线程中栈空间变量p的地址传递到了子线程中,在子线程中将要传递出的数据写入到了这块内存中。
也就是说在程序的main()函数中,通过指针变量ptr或者通过结构体变量p都可以读出子线程传出的数据。


5. 线程分离

在某些情况下,程序中的主线程有属于自己的业务处理流程,如果让主线程负责子线程的资源回收,调用pthread_join()只要子线程不退出主线程就会一直被阻塞,主要线程的任务也就不能被执行了。
在线程库函数中为我们提供了线程分离函数pthread_detach(),调用这个函数之后指定的子线程就可以和主线程分离,当子线程退出的时候,其占用的内核资源就被系统的其他进程接管并回收了。线程分离之后在主线程中使用pthread_join()就回收不到子线程资源了。

#include <pthread.h>
// 参数是子线程的线程ID, 主线程就可以和这个子线程分离了
int pthread_detach(pthread_t thread);
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

// 子线程的处理代码
void* working(void* arg)
{
    printf("我是子线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<9; ++i)
    {
        printf("child == i: = %d\n", i);
    }
    return NULL;
}

int main()
{
    // 1. 创建一个子线程
    pthread_t tid;
    pthread_create(&tid, NULL, working, NULL);

    printf("子线程创建成功, 线程ID: %ld\n", tid);
    // 2. 子线程不会执行下边的代码, 主线程执行
    printf("我是主线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<3; ++i)
    {
        printf("i = %d\n", i);
    }

    // 设置子线程和主线程分离
    pthread_detach(tid);

    // 让主线程自己退出即可
    pthread_exit(NULL);
    
    return 0;
}

6. 其他线程函数

6.1 线程取消

线程取消的意思就是在某些特定情况下在一个线程中杀死另一个线程。
使用这个函数杀死一个线程需要分两步:
在线程A中调用线程取消函数pthread_cancel,指定杀死线程B,这时候线程B是死不了的
在线程B中进程一次系统调用(从用户区切换到内核区),否则线程B可以一直运行。

#include <pthread.h>
int pthread_cancel(pthread_t thread);
  • 参数:要杀死的线程的线程ID
  • 返回值:函数调用成功返回0,调用失败返回非0错误号。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>

// 子线程的处理代码
void* working(void* arg)
{
    int j=0;
    for(int i=0; i<9; ++i)
    {
        j++;
    }
    // printf函数会调用系统函数, 因此这是个间接的系统调用
    printf("我是子线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<9; ++i)
    {
        printf(" child i: %d\n", i);
    }

    return NULL;
}

int main()
{
    // 1. 创建一个子线程
    pthread_t tid;
    pthread_create(&tid, NULL, working, NULL);

    printf("子线程创建成功, 线程ID: %ld\n", tid);
    // 2. 子线程不会执行下边的代码, 主线程执行
    printf("我是主线程, 线程ID: %ld\n", pthread_self());
    for(int i=0; i<3; ++i)
    {
        printf("i = %d\n", i);
    }

    // 杀死子线程, 如果子线程中做系统调用, 子线程就结束了
    pthread_cancel(tid);

    // 让主线程自己退出即可
    pthread_exit(NULL);
    
    return 0;
}

关于系统调用有两种方式:

  • 直接调用Linux系统函数
  • 调用标准C库函数,为了实现某些功能,在Linux平台下标准C库函数会调用相关的系统函数

6.2 线程ID的比较

在Linux中线程ID本质就是一个无符号长整形,因此可以直接使用比较操作符比较两个线程的ID,但是线程库是可以跨平台使用的,在某些平台上 pthread_t可能不是一个单纯的整形,这中情况下比较两个线程的ID必须要使用比较函数

#include <pthread.h>
int pthread_equal(pthread_t t1, pthread_t t2);
  • 参数:t1 和 t2 是要比较的线程的线程ID
  • 返回值:如果两个线程ID相等返回非0值,如果不相等返回0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/901693.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言入门教程,C语言学习教程(非常详细)第二章 c语言初探

第一个C语言程序 我们有两种方式从计算机获得信息&#xff1a;一是看屏幕上的文字、图片、视频等&#xff0c;二是听从喇叭发出来的声音。让喇叭发出声音目前还比较麻烦&#xff0c;我们先来看看如何在屏幕上显示一些文字吧。 在屏幕上显示文字非常简单&#xff0c;只需要一个…

npm 不是内部或外部命令,也不是可运行的程序或批处理文件。

遇到问题&#xff1a; 1.遇到问题&#xff1a;npm 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。 2.遇到问题&#xff1a;或者使用npm安装插件时会出现 XXX\node\node_modules\npm不可用 情况 如下图&#xff1a; 分析问题&#xff1a; nodejs在nodejs官网…

Python内置库介绍——random库

Content 0. 前言1. random.random()2. random.randint(a, b)3. random.choice(seq)4. random.shuffle(seq)5. random.sample(population, k)6. random.uniform(a, b)7. random.seed(x)8. 使用实例&#xff1a;随机生成用户初始账号和初始密码 0. 前言 操作系统&#xff1a;Win…

Leecode找出字符串中第一个匹配项的下标 即实现strSTR()函数

目录 简单介绍该函数的作用 在我们去用关键词查找微信或者qq聊天记录的时候&#xff0c;我们总不能一句一句去找吧。我们需要用到的功能底层大概是此博客所讲的这个函数熬。 一.算法需要传入的参数和返回类型 需要传入的就是关键词和所有的文本&#xff0c;返回的是当前关键词…

IDEA源码下载失败问题

1.IDEA下载源码报 java.lang.RuntimeException: Cannot reconnect java.lang.RuntimeException: Cannot reconnect 异常通常表示无法重新连接到资源或服务。这种情况可能出现在尝试重新连接到数据库、网络套接字或任何需要连接的资源时。 以下是解决此异常的几种可能方法&…

经典LeetCode在线OJ习题

目录 习题一&#xff1a;移除元素 &#xff08;一&#xff09;、题目 &#xff08;二&#xff09;、示例 &#xff08;三&#xff09;、解题思路 思路一&#xff1a; 思路一源代码&#xff1a; 源代码解释&#xff1a; 思路二&#xff1a;&#xff08;最标准最适用&#…

利用metasploit生成反弹shell程序,实现远程控制

1. 关于metasploit Metasploit是一款开源的渗透测试框架&#xff0c;由Rapid7公司开发和维护。它提供了一套强大的工具和资源&#xff0c;用于评估和测试计算机系统的安全性。Metasploit的目标是帮助安全专业人员发现和利用系统中的漏洞&#xff0c;以便改进系统的安全性。 Met…

Mybatis的SqlSource SqlNode BoundSql

学习链接 MyBatis SqlSource解析 【Mybatis】Mybatis源码之SqlSource#getBoundSql获取预编译SQL Mybatis中SqlSource解析流程详解 Mybatis TypeHandler解析 图解 Mybatis的SqlSource&SqlNode - processon DynamicSqlSource public class DynamicSqlSource implement…

【leetcode 力扣刷题】哈希表初尝试

哈希表 刷题初尝试 哈希表基础知识242. 有效的字母异位词383. 赎金信49. 字母异位词分组438. 找到字符串中所有字母异位词 哈希表基础知识 哈希表是一种数据结构&#xff0c;也叫散列表。哈希表中存储的是键值对&#xff0c;即(key&#xff0c;value)&#xff0c;根据key直接查…

7-1 选择法排序

分数 20 全屏浏览题目 切换布局 作者 C课程组 单位 浙江大学 本题要求将给定的n个整数从大到小排序后输出。 输入格式&#xff1a; 输入第一行给出一个不超过10的正整数n。第二行给出n个整数&#xff0c;其间以空格分隔。 输出格式&#xff1a; 在一行中输出从大到小有序…

openai多模态大模型:clip详解及使用

引言 CLIP全称Constrastive Language-Image Pre-training&#xff0c;是OpenAI推出的采用对比学习的文本-图像预训练模型。CLIP惊艳之处在于架构非常简洁且效果好到难以置信&#xff0c;在zero-shot文本-图像检索&#xff0c;zero-shot图像分类&#xff0c;文本→图像生成任务…

JAVA基础知识(五)——面向对象(中)

面向对象&#xff08;中&#xff09; 一、面向对象特征之一&#xff1a;封装与隐藏1.1 简介1.2 封装性的体现1.3 四种访问权限修饰符 二、类的成员之三&#xff1a;构造器2.1 构造器的特征2.2 构造器的作用2.3 语法格式2.4 构造器分类2.5 构造器重载2.6 属性赋值过程 三、扩展知…

Python的六种参数?

很多人说&#xff0c;Python的参数类型有四种、五种&#xff0c;我个人认为归纳起来是六种参数&#xff0c;分别为&#xff1a;位置参数&#xff08;Positional Arguments&#xff09;、默认参数&#xff08;Default Arguments&#xff09;、关键字参数&#xff08;Keyword Arg…

[C++11]

文章目录 1. 自动类型推导1.1 auto1.1.1 推导规则1.1.2 auto的限制1.1.3 auto的应用1.1.4 范围for 1.2 decltype1.2.1 推导规则1.2.2 decltype的应用 1.3 返回类型后置 2.可调用对象包装器、绑定器2.1 可调用对象包装器2.1.1 基本用法2.1.2 作为回调函数使用 2.2 绑定器 3. usi…

系统架构设计专业技能 · 信息系统基础

系列文章目录 系统架构设计专业技能 网络技术&#xff08;三&#xff09; 系统架构设计专业技能 系统安全分析与设计&#xff08;四&#xff09;【系统架构设计师】 系统架构设计高级技能 软件架构设计&#xff08;一&#xff09;【系统架构设计师】 系统架构设计高级技能 …

vue 关闭prettier警告warn

这个就是我们创建vue cli的时候 把这个给默认上了 关闭这个只需在.eslintrc.js页面里边添加一行代码"prettier/prettier": "off"

Mac OS 中JDK 环境(jdk 1.8.0_831)安装配置、环境变量配置及卸载操作

前言&#xff1a; 摊牌了&#xff0c;本来就有点喜新厌旧的我&#xff0c;特意把系统和开发环境都拉到比较高&#xff0c;想试验一下兼容性和某些新特性&#xff0c;探索了一下新大陆&#xff0c;也见识了各种光怪陆离的妖魔鬼怪。 因为要着手云平台项目的重构改版和新系统的架…

5G技术与其对智能城市、物联网和虚拟现实领域的影响

随着第五代移动通信技术&#xff08;5G&#xff09;的到来&#xff0c;我们即将迈向一个全新的数字化世界。5G技术的引入将带来更高的速度、更低的延迟和更大的连接性&#xff0c;推动了智能城市、物联网和虚拟现实等领域的发展。 首先&#xff0c;5G技术将带来超越以往的网络速…

global 可不能随便用啊!寻找1-10000内的 Spyder 数遇到的小问题,却是大思考

今天遇到这样一个问题&#xff1a;寻找1-10000内的 Spyder 数&#xff0c;Spyder 数是指&#xff0c;如果将一个数的每个位上的数字相乘&#xff0c;再将这些乘积相加&#xff0c;最终得到的和等于原始数&#xff0c;那么该数就是 Spyder 数。 逻辑分析 这个逻辑其实很简单&…

软考A计划-系统集成项目管理工程师-法律法规-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…