【线程】线程概念及相关函数实现

news2024/12/23 17:26:44

目录

0. 线程的概念

1. 线程的基本操作

1.1 线程的创建:pthread_create函数

1.2 线程等待:pthread_join函数

1.3 线程的分离:pthread_detach函数

1.4 线程退出:pthread_exit函数

1.5 线程的取消:pthread_cancel函数

1.6 线程取消状态:pthread_setcancelstate函数

1.7 线程的取消点:pthread_testcancel函数

1.8 线程的取消类型:pthread_setcanceltype函数

1.9 线程退出清理函数:pthread_cleanup_push和pthread_cleanup_pop函数

1.9.1 调用pthread_exit函数时,系统自动调用线程清理函数

1.9.2 线程被取消时,系统自动调用线程清理函数

1.9.3 调用pthread_cleanup_pop函数时,系统自动调用线程清理函数

总结:


0. 线程的概念

线程的概念

  • 每一个进程都拥有自己的数据段、代码段和堆栈段,这就造成进程在进行创建、切换、撤销操作时,需要较大的系统开销。
  • 为了减少开销,从进程中演化出了线程。
  •  线程存在于进程中,共享进程的资源。
  •  线程是进程中的独立控制流,由环境(包括寄存器组和程序计数器)和一系列的执行指令组成。
  •  每一个进程有一个地址空间和一个控制线程。

线程和进程的比较

调度:

        线程是CPU调度和分派的基本单位。

拥有资源:

        进程是系统中程序执行和资源分配的基本单位。

        线程自己一般不拥有资源(除了必不可少的程序计数器,一组寄存器和栈),但它可以去访问其所属进程的资源,如进程代码段,数据段以及系统资源(已打开的文件,I/O设备等)。

系统开销:

        同一个进程中的多个线程可共享同一地址空间,因此它们之间的同步和通信的实现也变得比较容易。

        在进程切换时候,涉及到整个当前进程CPU环境的保存以及新被调度运行的进程的CPU环境的设置;而线程切换只需要保存和设置少量寄存器的内容,并不涉及存储器管理方面的操作,从而能更有效地使用系统资源和提高系统的吞吐量。

并发性:

        不仅进程间可以并发执行,在一个进程中的多个线程之间也可以并发执行。

总结:

        一般把线程称之为轻量级的进程。

        一个进程可以创建多个线程,多个线程共享一个进程的资源。

        每一个进程创建的时候系统会给其4G虚拟内存,3G用户空间是私有的,所以进程切换时,用户空间也会切换,所以会增加系统开销,而一个进程中的多个线程共享一个进程的资源,所以线程切换时不用切换这些资源,效率会更高。

        线程的的调度机制和进程是一样的,多个线程来回切换运行。

多线程的用处:

多任务程序的设计:

        一个程序可能要处理应用,要处理多种任务,如果开发不同的进程来处理,系统开销很大,数据共享,程序结构都不方便,这时可使用多线程编程方法。

并发程序设计:

        一个任务可能分成不同的步骤去完成,这些不同的步骤之间可能是松散耦合的,可能通过线程的互斥,同步并发完成。这样可以为不同的任务步骤建立线程。

网络程序设计:

        为提高网络的利用效率,我们可能使用多线程,多每一个连接使用一个线程去处理。

数据共享:

  • 同一个进程中的不同线程共享进程的数据空间,方便不同线程间的数据共享。
  • 在多CPU系统中,实现真正的并行。

1. 线程的基本操作

  1. 就像每个进程都有一个进程号一样,每个线程也有一个线程号。
  2. 进程号在整个系统中是唯一的,但线程号不同,线程好只在它所属的进程环境中有效。
  3. 进程号用pid_t数据类型表示,是一个非负整数。线程号则用pthread_t数据类型来表示。
  4. 有的系统在实现pthread_t的时候,用一个结构体来表示,所以在可移植的操作系统实现不能不能把它作为整数处理。

1.1 线程的创建:pthread_create函数

pthread_create函数:

#include<pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

功能:

        创建一个线程。

参数:

        thread:线程标识符地址。

        attr:线程属性结构体地址。

        start_routine:线程函数的入口地址。

        arg:传给线程函数的参数。

返回值:

        成功:0

        失败:非0

        与fork不同的是pthread_create创建的线程不与父线程在同一点开始运行,而是从指定的函数开始运行,该函数运行完后,该线程也就退出了。

        线程依赖进程存在的,如果创建线程的进程结束了,线程也就结束了。

        线程函数的程序在pthread库中,故链接时要加上参数-lpthread

代码示例:

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

void* thread_fun(void* arg)
{
    printf("son1 if running\n");
}
int main()
{
    printf("man if running \n");
    pthread_t thread;

    if (pthread_create(&thread, NULL, thread_fun, NULL) != 0)
    {
        perror("fail to pthread_create");
        exit(1);
    }
    while (1);
    return 0;
}

 执行截图:

线程的调度机制的验证

代码示例:

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


void* pthread_fun1(void* arg)
{
    printf("son1 if running\n");
    sleep(1);
    printf("*****************************\n");
}
void* pthread_fun2(void* arg)
{
    printf("son2 if running\n");
    sleep(1);
    printf("----------------------------\n");
}
int main()
{
    pthread_t thread1, thread2;

    if (pthread_create(&thread1, NULL, pthread_fun1, NULL) != 0)
    {
        perror("fail to pthread_create");
        exit(1);
    }

    if (pthread_create(&thread2, NULL, pthread_fun2, NULL) != 0)
    {
        perror("fail to pthread_create");
        exit(1);
    }
    while (1);
    return 0;
}

执行截图:

 线程处理函数的传参

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

int num = 100;
void* pthread_fun1(void* srg)
{
    printf("son1:num = %d\n", num);
    num++;
    int n = *(int*)srg;
    printf("son1 n = %d\n", n);
}
void* pthread_fun2(void* arg)
{
    sleep(1);
    printf("son2:num =%d\n", num);
    int n = *(int*)arg;
    printf("son2 n = %d\n", n);
}

int main()
{
    pthread_t thread1, thread2;
    int a = 555;

    if (pthread_create(&thread1, NULL, pthread_fun1, (void*)&a) != 0)
    {
        perror("'fail too pthred_creat");
        exit(1);
    }
    if (pthread_create(&thread2, NULL, pthread_fun2, (void*)&a) != 0)
    {
        perror("fail to pthread_crateee");
        exit(1);
    }
    while (1);
    return 0;
}

执行截图:

1.2 线程等待:pthread_join函数

pthread_join函数

#include<pthread.h>

int pthread_join(pthread_t thread, void **retval);

功能:

        等待子线程结束,并回收子线程资源。

参数:

        thread:被等待的线程号。

        retval:用来存储线程退出状态的指针的地址。

返回值:

        成功:0

        失败:非0

代码示例:

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

void* thread_fun(void* arg)
{
    printf("son is running\n");
    sleep(3);
    printf("son will quit\n");
}
int main()
{
    printf("man is running\n");

    pthread_t thread;
    if (pthread_create(&thread, NULL, thread_fun, NULL) != 0)
    {
        perror("fail to pthhread_create");
        exit(1);
    }
    if (pthread_join(thread, NULL) != 0)
    {
        perror("fail toooo pthread_join");
        exit(1);
    }
    printf("man will quit\n");
    return 0;
}

执行截图:

获取子线程退出状态值

代码示例:

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

void* thread_fun(void* arg)
{
    static   int num = 666;
    printf("son is running\n");
    sleep(3);
    printf("son will quit\n");
    return (void*)&num;
}
int main()
{
    printf("man is running\n");

    pthread_t thread;
    if (pthread_create(&thread, NULL, thread_fun, NULL) != 0)
    {
        perror("fail to pthhread_create");
        exit(1);
    }
    int* num;
    if (pthread_join(thread, (void**)&num) != 0)
    {
        perror("fail toooo pthread_join");
        exit(1);
    }
    printf("ret_val = %d\n", *num);
    printf("man will quit\n");
    return 0;
}

执行截图:

1.3 线程的分离:pthread_detach函数

线程的结合态和分离态

Linux线程执行和Windows不同,pthread有两种状态:

可结合的(joinable)或者时分离的(detached),线程默认创建为可结合态。

        如果线程时joinable状态,当线程函数自己返回退出时或pthread_exit时都不会释放线程所占用堆栈和线程描述符(总计8K多)。只有当你调用 了pthread_join之后这些资源才会被释放。

        如果是detached状态的线程,这些资源在线程函数退出时或pthread_exit时自动会被释放,使用pthread_detach函数将线程设置为分离态。

创建一个线程后应回收其资源,但使用pthread_join函数会使调用者阻塞,故Linux提供了线程分离函数:

pthread_detach函数

#include<pthread.h>

int pthread_detach(pthread_t thread);

功能:

        使调用线程与当前进程分离,使其成为一个独立的线程,该线程终止时,系统将自动回收它的资源。

参数:

        thread:线程号。

返回值:

        成功:0

        失败:非0 

代码示例:

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

void* pthread_fun(void* arg)
{
    printf("son is running\n");
    sleep(2);
    printf("son will quite\n");
}
int main()
{
    printf("man is running\n");
    pthread_t thread;
    if (pthread_create(&thread, NULL, pthread_fun, NULL) != 0)
    {
        perror("fail to pthread_create\n");
        exit(1);
    }
//这里就不需要再执行pthread_join了
    if (pthread_detach(thread) != 0)
    {
        perror("fail to pthread_detach\n");
        exit(1);
    }
    while (1)
    {
        printf("hello world\n");
        sleep(1);
    }


    return 0;
}

 执行截图:

1.4 线程退出:pthread_exit函数

        在进程中我们可以调用exit函数或_exit函数来结束进程,在一个线程中我们可以通过以下三种在不终止整个进程的情况下停止它的控制流。

  1. 线程从执行函数中返回
  2. 线程调用pthread_exit退出线程
  3. 线程可以被同一进程中的其他线程取消

线程退出函数:pthread_exit函数

#include<pthread.h>

void pthread_exit(void *retval);

功能:

        退出调用线程。

参数:

        retval:存储线程退出状态的指针。

注:       

        一个进程中的多个线程时共享该进程的数据段,因此,通常线程退出后所占用的资源并不会释放。

        如果要释放资源,结合态要通过pthread_join函数,分离态则自动释放。代码示例:

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

void* pthread_fun(void* arg)
{
    static char buf[] = "this thread has quied";
    printf("son if running\n");
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        if (i == 5)
        {
            //      pthread_exit(NULL);
            pthread_exit(buf);
        }
        printf("**********************\n");
        sleep(1);
    }
}
int main()
{
    printf("man is running\n");
    pthread_t thread;
    if (pthread_create(&thread, NULL, pthread_fun, NULL) != 0)
    {
        perror("fail to pthread_create");
        exit(1);
    }
    char* str;
    pthread_join(thread, (void**)&str);
    printf("str = %s\n", str);
    printf("man will quit\n");

    return 0;
}

执行截图:

1.5 线程的取消:pthread_cancel函数

取消线程是指取消一个正在执行线程的操作。

#include<pthread.h>

int pthread_cancel(pthread_t thread);

功能:

        取消线程。

参数:

        thread:目标线程ID。

返回值:

        成功:0

        失败:出错编号

pthread_cancel函数的实质是发信号给目标线程thread,使目标线程退出。

此函数只是发送终止信号给目标线程,不会等待取消目标线程执行完才返回。

        然而发送成功并不意味着目标线程一定就会终止,线程被取消时,线程的取消属性会决定线程能否被取消以及何时被取消。

线程的取消状态:

        即线程能不能被取消。

线程的取消点:

        即线程被取消的地方。

线程的取消类型:

        在线程能被取消的状态下,是立马被取消还是执行到取消点的时候被取消结束。

代码示例:

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

void* pthread_fun(void* arg)
{
    while (1)
    {
        printf("son is running\n");
        sleep(1);
    }
}

int main()
{
    pthread_t  thread;
    if (pthread_create(&thread, NULL, pthread_fun, NULL) != 0)
    {
        perror("fail to pthread_create");
        exit(1);
    }
    sleep(3);
//任意线程都可以尝试取消
    pthread_cancel(thread);
    pthread_join(thread, NULL);
    return 0;

}

执行截图:

1.6 线程取消状态:pthread_setcancelstate函数

        在Linux系统下,线程默认可以被取消,编程时可以通过pthread_setcancelstate函数设置线程是否可以被取消

#include<pthread.h>

int pthread_setcancelstate(int state, int *oldstate);

功能:

        设置线程是否可以被取消。

参数:

        state:新的状态。

                PTHREAD_CANCEL_DISABLE:不可以被取消。

                PTHREAD_CANCEL_ENABLE:可以被取消。

        oldstate:保存调用线程原来的可取消状态的内存地址。

返回值:

        成功:0

        失败:非0

代码示例:

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

void* pthread_fun(void* arg)
{
    //      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    while (1)
    {
        printf("son is running\n");
        sleep(1);
    }
}

int main()
{
    pthread_t  thread;
    if (pthread_create(&thread, NULL, pthread_fun, NULL) != 0)
    {
        perror("fail to pthread_create");
        exit(1);
    }
    sleep(3);
    pthread_cancel(thread);
    pthread_join(thread, NULL);
    return 0;

}

执行截图:

1.7 线程的取消点:pthread_testcancel函数

        线程被取消后,该线程并不是马上终止,默认情况下线程执行到取消点时才能被终止。编程时可以通过pthread_testcancel函数设置线程的取消点。

void pthread_testcancel(void);

#include<pthread.h>
void pthread_testcancel(void);

功能:设置线程的取消点。

参数:无

返回值:无

当别的线程取消调用此函数的线程时候,被取消的线程执行到此函数时结束。

POSIX. 1保证线程调用表1、表2中的任何函数时,取消点都会出现。

表1:

 表2:

 代码示例:

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

void* pthread_fun(void* arg)
{
    while (1)
    {
        printf("son is running\n");
        sleep(1);
        pthread_testcancel();
    }
}

int main()
{
    pthread_t  thread;
    if (pthread_create(&thread, NULL, pthread_fun, NULL) != 0)
    {
        perror("fail to pthread_create");
        exit(1);
    }
    sleep(3);
    pthread_cancel(thread);
    pthread_join(thread, NULL);
    return 0;

}

执行截图:

1.8 线程的取消类型:pthread_setcanceltype函数

        线程被取消后,该线程并不是马上终止,默认情况下线程执行到取消点时才能被终止。编程时可以通过pthread_setcanceltype函数设置线程是否可以立即被取消。

#include<pthread.h>

int pthread_setcanceltype(int type, int *oldtype);

功能:

        type:类型

                PTHREAD_CANCEL_ASYNCHRONOUS:立即取消。

                PTHREAD_CANCEL_DEFERRED:不立即取消。

        oldtype:保存调用线程原来的可取消类型的内存地址。

返回值:

        成功:0

        失败:非0

代码示例:

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

void* pthread_fun(void* arg)
{
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

    //      pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    while (1)
    {
        printf("son is running\n");
        sleep(1);
    }
}

int main()
{
    pthread_t  thread;
    if (pthread_create(&thread, NULL, pthread_fun, NULL) != 0)
    {
        perror("fail to pthread_create");
        exit(1);
    }
    sleep(3);
    pthread_cancel(thread);
    pthread_join(thread, NULL);
    return 0;

}

执行截图:

1.9 线程退出清理函数:pthread_cleanup_push和pthread_cleanup_pop函数

        和进程的退出清理一样,线程也可以注册它退出时要调用的函数,这样的函数称为线程清理处理程序(thread cleanup handler)。

注意:

        线程可以建立多个清理处理程序。

        处理程序在栈中,故它们的执行顺序与它们的注册时顺序相反。

#include<pthread.h>

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

功能:

        将清除函数压栈。即注册清理函数。

参数:

        routine:线程清理函数的指针。

        arg:传给线程清理函数的参数。

弹出清理函数

#include<pthread.h>

void pthread_cleanup_pop(int execute);

功能:

        将清除函数弹栈,即删除清理函数。

参数:

        execute:线程清理函数执行标志位。

        非0,弹出清理函数,执行清理函数。

        0,弹出清理函数,不执行清理函数。

当线程执行以下动作时会调用清理函数:

  1. 调用pthread_exit退出进程。
  2. 响应其他线程的取消请求。
  3. 用非零execute调用pthread_cleanup_pop

        无论哪种情况pthread_cleanup_pop都将删除上一次pthread_cleanup_push调用组测的清理处理函数。

1.9.1 调用pthread_exit函数时,系统自动调用线程清理函数

代码示例:

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

void mycleanup(void* arg)
{
    printf("cleann up ptr = %s\n", (char*)arg);
    free((char*)arg);
}
void* pthread_fun(void* arg)
{
    char* ptr = NULL;
    printf("this is new thread\n");
    ptr = (char*)malloc(100);
    pthread_cleanup_push(mycleanup, (void*)(ptr));
    memset(ptr, 0, 100);
    strcpy(ptr, "memory from malloc");
    sleep(3);
    printf("before exit\n");

    pthread_exit(NULL);
    printf("before pop\n");
    pthread_cleanup_pop(1);
}
int main()
{
    pthread_t thread;
    pthread_create(&thread, NULL, pthread_fun, NULL);
    pthread_join(thread, NULL);
    printf("process is dying\n");
    return 0;
}

执行截图:

1.9.2 线程被取消时,系统自动调用线程清理函数

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

void mycleanup(void* arg)
{
    printf("cleann up ptr = %s\n", (char*)arg);
    free((char*)arg);
}
void* pthread_fun(void* arg)
{
    char* ptr = NULL;
    printf("this is new thread\n");
    ptr = (char*)malloc(100);
    pthread_cleanup_push(mycleanup, (void*)(ptr));
    memset(ptr, 0, 100);
    strcpy(ptr, "memory from malloc");
    sleep(10);

    //      pthread_exit(NULL);

    printf("before pop\n");
    pthread_cleanup_pop(1);
}
int main()
{
    pthread_t thread;
    pthread_create(&thread, NULL, pthread_fun, NULL);
    sleep(5);
    printf("before cancel\n");
    pthread_cancel(thread);
    pthread_join(thread, NULL);
    printf("process is dying\n");
    return 0;
}

 执行截图:

1.9.3 调用pthread_cleanup_pop函数时,系统自动调用线程清理函数

代码示例:

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

void cleanup_func1(void* arg)
{
    printf("in clanup func1\n");
    printf("clean up ptr = %s\n", (char*)arg);
    free((char*)arg);
}
void cleanup_func2(void* arg)
{
    printf("in cleanup func2\n");
}
void* pthread_fun(void* arg)
{
    char* ptr = NULL;
    printf("this is new thread\n");
    ptr = (char*)malloc(100);
    pthread_cleanup_push(cleanup_func1, (void*)(ptr));
    pthread_cleanup_push(cleanup_func2, (void*)(ptr));
    memset(ptr, 0, 100);
    strcpy(ptr, "memory from malloc");

    sleep(3);
    printf("before pop\n");
    pthread_cleanup_pop(1);
    printf("before pop\n");
    pthread_cleanup_pop(1);
}
int main()
{
    pthread_t thread;
    pthread_create(&thread, NULL, pthread_fun, NULL);
    pthread_join(thread, NULL);
    printf("process is dying\n");
    return 0;
}

执行截图:

总结:

         在本篇博客中,我们详细介绍了线程编程中的相关函数。通过了解和掌握这些函数,我们能够更灵活地创建、管理和同步线程,实现并发编程和多任务处理。这些函数包括线程的创建、启动、等待和终止等,是编写多线程应用程序的关键工具。

        掌握线程函数的使用方法可以帮助我们构建高效、可靠的多线程应用程序,并充分利用计算资源来提升性能。这些函数的灵活应用使我们能够实现线程间的协调和通信,避免竞态条件和死锁等并发编程中常见的问题。

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

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

相关文章

了解Spring

目录 什么是Spring? DI Spring 存与取 spring 的存操作 spring的取操作 更快速的进行 Spring 存 与 读 三大注入方式 Autowired set 注入 构造方法注入 Spring 容器中有多个相同的类时 Bean 作用域 设置作用域 Spring 执行流程 Bean 生命周期 什么是Spring? Sp…

【密码学基础】半/全同态加密算法基础学习笔记

文章目录 1 半同态加密Pailliar加法同态加密Paillier加解密过程Paillier的同态性Paillier的安全性 El Gamal乘法同态加密RSA乘法同态加密 2 全同态加密BFV全同态加密BFV的编码方式BFV加解密过程BFV的安全性BFV的同态性自举Bootstrapping 3 同态加密应用场景场景1&#xff1a;安…

【maven】安装、使用和常用命令

安装 windows 下载Maven二进制文件 前往Apache Maven官方网站 (https://maven.apache.org) &#xff0c;找到最新的稳定版本&#xff0c;然后下载对应的二进制压缩包&#xff08;如apache-maven-3.8.2-bin.zip&#xff09;。解压缩文件 将下载的压缩包解压到你选择的目录&…

QCC51XX---chain修改

QCC51XX---系统学习目录_嵌入式学习_force的博客-CSDN博客 如何去修改音频chain链路,就是那种想多加几条输入源或输出,又或者把当前的输入输出换到别的地方的那种应用。例如一个自带mic的dongle,或者模拟输入的LE dongle。 如果要改某个状态下的音频链路,那就需要先找出默认…

修复常见 Android 问题的 9 款顶级 Android 手机维修软件

许多人发现Android手机或平板电脑上的Android操作系统一开始运行得很好&#xff0c;但随着时间的推移&#xff0c;可能会出现各种Android系统问题。您可能会遇到一些问题&#xff0c;例如系统速度变慢、启动无响应、挂起错误、界面冻结、短信停滞、应用程序崩溃等。那么&#x…

Linux学习之内存查看命令free和top

我用来演示的系统使用CentOS Linux release 7.6.1810 (Core)&#xff0c;内核版本是3.10.0-957.el7.x86_64。 Linux在进程申请内存的时候&#xff0c;一般都是尽可能给进程内存&#xff0c;因为进程在申请内存的时候有损耗。 free free命令可以看以k为单位的内存。 free -…

使用less命令搜索文件中的关键字

目录 介绍常用搜索技巧实例 介绍 less 与 more 类似&#xff0c;less 可以随意浏览文件&#xff0c;支持翻页和搜索&#xff0c;支持向上翻页和向下翻页。 语法 less [参数] 文件 参数说明&#xff1a; -b <缓冲区大小> 设置缓冲区的大小 -e 当文件显示结束后&#xff…

STM32 USART

USART.C 文件中只是针对串口1&#xff0c;使用其他串口需要稍作修改 IC、SPI主要用于一块开发板上两个芯片之间的通信&#xff0c;例如&#xff1a;主控和传感器之间的通信 串口适用于两块开发板之间的通信&#xff0c;或者说开发板和上位机之间的通信&#xff0c;有线通信 以…

MAC OS X 这个“安装 macOS Xxx Xxx”应用程序副本已损坏,不能用来安装 macOS,超级终端修改日期date 已解决

原因&#xff1a;旧版 macOS 证书已经过期 解决方法&#xff1a;断开互联网&#xff0c;修改系统时间 date 102013142018.20 说明&#xff1a;10是月&#xff0c;20是日&#xff0c;13是时&#xff0c;14是分&#xff0c;2018是年&#xff0c;20是秒 输入上面的代码按回车后…

【ARM】-异常与中断

文章目录 中断中断请求、中断源中断服务程序保存现场、恢复现场中断仲裁、中断优先级中断嵌套 异常广义上的异常同步异常异步异常精确异步异常&#xff08;Precise Asynchronous Exception&#xff09;非精确异步异常&#xff08;Imprecise Asynchronous Exception&#xff09;…

发展零碳数据中心,超聚变推动液冷规模商用

算力的发展犹如一体两面。 一方面&#xff0c;在数字经济、产业数字化和数字化转型中&#xff0c;算力发挥着关键的引擎作用&#xff1b;另一方面&#xff0c;持续增长的多元异构算力需求、不断提升的算力密度以及逐渐成体系的算力网络&#xff0c;也带来了不可低估的长期能耗…

Linux基础笔记

已经有很长很长一段时间没有更新帖子了&#xff0c;一眨眼2023 已经过半&#xff0c;这些日子里&#xff0c;有太多太多事情要做了&#xff0c;今年只更新了几篇&#xff0c;这几天刚好有空&#xff0c;浅浅更新一篇叭&#xff01;~~~ 首先&#xff0c;Linux是一种开源的操作系…

测试开发工程必备技能之一:Mock的使用

目录 1. 背景 2. Mock是什么 3. Mock能做什么 4. Mock实现方式 5. Mock市面上常见的解决方案 6. Python下unittest.mock使用 总结&#xff1a; 1. 背景 在实际产品开发过程中&#xff0c;某个服务或前端依赖一个服务接口&#xff0c;该接口可能依赖多个底层服务或模块&…

K8S | 容器和Pod组件

对比软件安装和运行&#xff1b; 一、场景 作为研发人员&#xff0c;通常自己电脑的系统环境都是非常复杂&#xff0c;在个人的习惯上&#xff0c;是按照下图的模块管理电脑的系统环境&#xff1b; 对于「基础设施」、「主机操作系统」、「系统软件」来说&#xff0c;通常只做…

MYSQL根据标签查询数据

场景条件&#xff1a; 1.根据用户id查询到该id绑定的标签&#xff08;可能是多个标签也可能是单个标签&#xff09; 2.根据标签的id查询到绑定标签id的信息表 SELECT labelID FROM LRrelation WHERE relationID 1 SELECT * FROM notification SELECT * FROM notification…

解决GitHub下载速度太慢问题的方法汇总(持续更新,建议收藏)

文章目录 前言一、使用 git clone --depth1 来下载二、修改host文件解决三、谷歌浏览器插件加速四、油猴插件和脚本五、gitclone.com六、Github 加速下载链接七、Github 镜像访问八、使用码云下载参考资料&#xff0c;感谢以下文章 前言 Github上下载仓库或者克隆仓库&#xf…

运输层:TCP流量控制

1.运输层&#xff1a;TCP流量控制 笔记来源&#xff1a; 湖科大教书匠&#xff1a;TCP流量控制 流量控制(flow control)就是让发送方的发送速率不要太快&#xff0c;要让接收方来得及接收。 实现方法&#xff1a;滑动窗口机制 移动发送窗口&#xff0c;因接收窗口大小为300&am…

C++思维,作业7.3

#include <iostream> #include <cstring> using namespace std; int monster_blood10000; //英雄 class Hero { protected:string name;int hp;int attck; public:Hero(){//cout << "Hero的无参构造" << endl;}Hero(string name,int hp,int …

《Pytorch深度学习和图神经网络(卷 1)》学习笔记——第七章

这一章内容有点丰富&#xff0c;多用了一些时间&#xff0c;实例就有四五个。 这章内容是真多啊&#xff01;&#xff08;学完之后又回到开头感叹&#xff09; 大脑分级处理机制&#xff1a; 将图像从基础像素到局部信息再到整体信息 即将图片由低级特征到高级特征进行逐级计…

代码评审的18个军规,收藏好!

前言 大家好&#xff01; 我们开发完需求&#xff0c;提测前&#xff0c;一般都需要代码评审。小伙伴们&#xff0c;你们知道代码评审&#xff0c;一般都有哪些军规嘛&#xff1f;今天田螺哥给你带来代码评审的18个军规。 公众号&#xff1a;捡田螺的小男孩 &#xff08;有田…