《Linux操作系统编程》 第十章 线程与线程控制: 线程的创建、终止和取消,detach以及线程属性

news2025/2/22 1:13:17

在这里插入图片描述

在这里插入图片描述

🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁
🦄 个人主页——libin9iOak的博客🎐
🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺
🌊 《IDEA开发秘籍》学会IDEA常用操作,工作效率翻倍~💐
🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批评指正!🍁🐥

在这里插入图片描述

文章目录

  • 第十章 线程与线程控制
    • 学习目的
    • 学习要求
    • 学习方法
    • 概念和原理
      • 10.1 线程概述
        • 10.1.1 线程的引入
        • 10.1.2 线程的共享问题
        • 10.1.3 线程的数据共享
        • 10.1.4 线程的互斥问题
      • 10.2 线程和进程的比较
        • 10.2.1 线程和进程的比较
        • 10.2.2 线程的属性
      • 10.3 线程的状态与组成
        • 10.3.1 线程的状态
        • 10.3.2 线程的组成
      • 10.4 线程的创建与终止
        • 10.4.1 线程的创建
        • 10.4.2 线程的终止
      • 10.5 线程的属性
      • 10.6 死锁
        • 10.6.1 死锁的定义
        • 10.6.2 产生死锁的原因和必要条件
        • 10.6.3 处理死锁的基本方法
      • 10.7 线程间的同步和互斥
        • 10.7.1 互斥锁
        • 10.7.2 条件变量
        • 10.7.3 信号量机制
      • 10.8 Linux下的多线程编程
        • 10.8.1 Linux下的多线程编程
    • 重点
    • 难点
    • 习题
  • 原创声明

第十章 线程与线程控制

学习目的

​ 通过对线程与线程控制的相关知识点的编程学习和锻炼,培养学生们对线程相关实例问题的分析与解决能力。

学习要求

了解:同一进程中的线程共享的资源。线程编程时存在的问题,进程与线程的比较,线程ID和线程是否相同的判断。

理解:线程退出时的清理机制;

掌握:线程的创建、终止和取消,detach以及线程属性。

学习方法

​ 本章的线程概念较为抽象,需要学生较强的抽象思维能力。多线程编程部分需要学生上机实践。

概念和原理

10.1 线程概述

10.1.1 线程的引入

​ 由于进程是一个资源的拥有者,因此在创建、撤销和切换中,系统必须为此付出较大的时间和空间的开销。

线程保留了并发的优点,避免了进程的高代价

10.1.2 线程的共享问题

▪ 进程内的所有线程共享进程的很多资源(这种共享又带来了同步问题)。

​ 线程间共享 线程私有

进程指令 线程ID

全局变量 寄存器集合(包括PC和栈指针)

打开的文件 栈(用于存放局部变量)

信号处理程序 信号掩码

当前工作目录 优先级

用户ID

10.1.3 线程的数据共享

​ 每个线程私有的数据和资源:线程ID、线程上下文(一组寄存器值的集合)、线程局部变量(存储在栈中)。

10.1.4 线程的互斥问题

​ 对全局变量进行访问的基本步骤

a) 将内存单元中的数据读入寄存器

b) 对寄存器中的值进行运算

c) 将寄存器中的值写回内存单元

10.2 线程和进程的比较

10.2.1 线程和进程的比较

(1) 调度

在传统的操作系统中,进程作为拥有资源和独立调度、分派的基本单位。而在引入线程的操作系统中,则把线程作为调度和分派的基本单位,而进程作为资源拥有的基本单位。

(2) 并发性

在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间亦可并发执行,使得操作系统具有更好的并发性,从而能更加有效地提高系统资源的利用率和系统的吞吐量。

(3) 拥有资源

一般而言,线程自己不拥有系统资源(也有一点必不可少的资源),但它可以访问其隶属进程的资源,即一个进程的代码段、数据段及所拥有的系统资源,如已打开的文件、I/O 设备等,可以供该进程中的所有线程所共享。

(4) 独立性

同一进程中的不同线程共享进程的内存空间和资源。

同一进程中的不同线程的独立性低于不同进程。

(5) 系统开销

线程的切换只需要保存和设置少量的寄存器内容,不涉及存储器管理方面的操作。

(6) 支持多处理机系统

一个进程分为多个线程分配到多个处理机上并行执行,可加速进程的完成。

10.2.2 线程的属性

(1) 轻型实体

线程自己基本不拥有系统资源,只拥有少量必不可少的资源:TCB,程序计数器、一组寄存器、栈。

(2) 独立调度和分派的基本单位

在多线程OS中,线程是独立运行的基本单位,因而也是独立调度和分派的基本单位。

(3) 可并发执行

同一进程中的多个线程之间可以并发执行,一个线程可以创建和撤消另一个线程。

(4) 共享进程资源

它可与同属一个进程的其它线程共享进程所拥有的全部资源。

10.3 线程的状态与组成

10.3.1 线程的状态

​ 线程运行时有以下3种状态:

  1. 执行状态:表示线程正获得CPU而运行;
  2. 就绪状态:表示线程已具备了各种运行条件,一旦获得CPU便可执行;
  3. 阻塞状态:表示线程在运行中因某事件而受阻,处于暂停执行的状态;

在这里插入图片描述

图10-1 线程的状态转换

10.3.2 线程的组成

线程必须在某个进程内执行

一个进程可以包含一个线程或多个线程

在这里插入图片描述

图10-2 单线程和多线程的进程模型

​ 每个线程有一个TCB结构,即线程控制块,用于保存自己私有的信息,主要由以下部分组成:

▪ 一个唯一的线程标识符

▪ 一组寄存器 :包括程序计数器、状态寄存器、通用寄存器的内容;

▪ 线程运行状态:用于描述线程正处于何种运行状态;

▪ 优先级:描述线程执行的优先程度;

▪ 线程专有存储器:用于保存线程自己的局部变量拷贝;

▪ 信号屏蔽:对某些信号加以屏蔽。

▪ 两个栈指针:核心栈、用户栈

(1) 线程ID

同进程一样,每个线程也有一个线程ID

进程ID在整个系统中是唯一的,线程ID只在它所属的进程环境中也是唯一的。

线程ID的类型是pthread_t,在Linux中的定义如下:

​ typedef unsigned long int pthread_t

(/usr/include/bits/pthreadtypes.h)

(2) 获取线程ID

pthread_self函数可以让调用线程获取自己的线程ID

函数原型

▪ 头文件:pthread.h

▪ pthread_t pthread_self();

返回调用线程的线程ID

(3) 比较线程ID

Linux中使用整型表示线程ID,而其他系统则不一定

FreeBSD 5.2.1、Mac OS X 10.3用一个指向pthread结构的指针来表示pthread_t类型。

为了保证应用程序的可移植性,在比较两个线程ID是否相同时,建议使用pthread_equal函数

(4) pthread_equal函数

该函数用于比较两个线程ID是否相同

函数原型

▪ 头文件:pthread.h

▪ int pthread_equal(pthread_t tid1, pthread_t tid2);

若相等则返回非0值,否则返回0

(5) 进程/线程控制操作对比

应用功能线程进程
创建pthread_createfork,vfork
退出pthread_exitexit
等待pthread_joinwait、waitpid
取消/终止pthread_cancelabort
读取IDpthread_self()getpid()
同步互斥/通信机制互斥锁、条件变量、读写锁无名管道、有名管道、信号、消息队列、信号量、共享内存

10.4 线程的创建与终止

10.4.1 线程的创建

▪ 在多线程OS环境下,应用程序在启动时,通常仅有一个“初始化线程”线程在执行。

▪ 在创建新线程时,需要利用一个线程创建函数(或系统调用),并提供相应的参数。

- 如指向线程主程序的入口指针、堆栈的大小,以及用于调度的优先级等。

▪ 在线程创建函数执行完后,将返回一个线程标识符供以后使用

▪ Linux下线程创建

- Linux系统下的多线程遵循POSIX线程接口,称为pthread。

#include <pthread.h>

int pthread_create(

​ pthread_t *restrict tidp, //指向线程标识符的指针
​ const pthread_attr_t *restrict attr, //设置线程属性
​ void *(*start_rtn)(void), //线程运行函数的起始地址
​ void *restrict arg; ) //运行函数的参数

10.4.2 线程的终止

▪ 线程完成了自己的工作后自愿退出;

▪ 或线程在运行中出现错误或由于某种原因而被其它线程强行终止。

▪ 终止线程的方式有两种:

- 自愿退出 return , pthread_exit

void pthread_exit(void *rval_ptr);

由于pthread库不是Linux系统默认的库,连接时需要使用库libpthread.a,所以如果使用pthread_create、pthread_exit等函数时,在编译中要加-lpthread参数:
#gcc -o XXX -lpthread XXX.c

- 强行终止 pthread_cancel

▪ 父线程等待子线程终止

- 函数原型

- 头文件:pthread.h

- int pthread_join(pthread_t thread,void **rval_ptr);

- thread:需要等待的子线程ID

- rval_ptr:(若不关心线程返回值,可直接将该参数设置为空指针NULL)

- 若线程从启动线程通过return返回,rval_ptr指向的内存单元中存放的是线程的返回值

- 若线程被其它线程调用pthread_cancel取消,rval_ptr指向的内存单元存放常数PTHREAD_CANCELED

- 若线程通过自己调用pthread_exit函数终止,rval_ptr就是调用pthread_exit时传入的参数

- 调用该函数的父线程将一直被阻塞,直到指定的子线程终止

- 返回值

- 成功返回0,否则返回错误编号

▪ 取消线程

- 线程调用该函数可以取消同一进程中的其他线程(即让该线程终止)

- 函数原型

- 头文件: pthread.h

- int pthread_cancel(pthread_t tid);

- 参数与返回值

- tid:需要取消的线程ID

- 成功返回0, 出错返回错误编号

▪ 线程清理处理函数

- 线程清理处理函数的注册

- 头文件:pthread.h

- void pthread_cleanup_push(void (*rtn)(void *), void *arg);

- void pthread_cleanup_pop(int execute);

- 参数

- rtn:清理函数,无返回值,包含一个类型为指针的参数

- arg:当清理函数被调用时,arg将被传递给清理函数

10.5 线程的属性

(1) 线程属性

在这里插入图片描述

图10-3 POSIX规定的一些线程属性

(2) 初始化和销毁

▪ 函数原型

#include<pthread.h>

int pthread_attr_init(pthread_attr_t *attr);

int pthread_attr_destroy(pthread_attr_t *attr);

▪ 参数与返回值

- 成功返回0,否则返回错误编号

- attr:线程属性,确保attr指向的存储区域有效

- 为了移植性,pthread_attr_t结构对应用程序是不可见的,应使用设置和查询等函数访问属性

(3) 初始化线程属性对象

属性缺省值描述
scopePTHREAD_SCOPE_PROCESS新线程与进程中的其他线程发生竞争
detachstatePTHREAD_CREATE_JOINABLE线程可以被其它线程等待
stackaddrNULL新线程具有系统分配的栈地址
stacksize0新线程具有系统定义的栈大小
priority0新线程的优先级为0
inheritschedPTHREAD_EXPLICIT_SCHED新线程不继承父线程调度优先级
schedpolicySCHED_OTHER新线程使用优先级调用策略

(4) 获取线程栈属性

▪ 函数原型

#include<pthread.h>

int pthread_attr_getstack(

​ const pthread_attr_t *attr,

​ void **stackaddr, size_t *stacksize);

▪ 参数与返回值

- attr:线程属性

- stackaddr:该函数返回的线程栈的最低地址

- stacksize:该函数返回的线程栈的大小

- 成功返回0,否则返回错误编号

(5) 设置线程栈属性

▪ 函数原型

#include<pthread.h>

int pthread_attr_setstack(

​ const pthread_attr_t *attr,

​ void *stackaddr, size_t *stacksize);

▪ 当用完线程栈时,可以再分配内存,并调用本函数设置新建栈的位置

▪ 参数与返回值

- attr:线程属性

- stackaddr:新栈的内存单元的最低地址,通常是栈的开始位置;对于某些处理器,栈是从高地址向低地址方向伸展的,stackaddr就是栈的结尾

- stacksize:新栈的大小

- 成功返回0,否则返回错误编号

(6) pthread_detach函数

▪ 函数原型

- 头文件:pthread.h

- int pthread_detach(pthread_t tid);

▪ 参数与返回值

- tid:进入分离状态的线程的ID

- 成功返回0,出错返回错误编号

10.6 死锁

10.6.1 死锁的定义

如果一组进程中的每一个进程都在等待仅由该组进程中的其它进程才能引发的事件,那么该组进程是死锁的。

10.6.2 产生死锁的原因和必要条件

▪ 原因

a) 竞争不可抢占性资源引起死锁

b) 竞争临时性(消耗性)资源引起进行死锁

c) 进程推进顺序不当引起死锁

▪ 必要条件

a) 互斥条件 :进程对分配到的资源进行排它性使用。

b) 请求和保持条件 :进程已经保持了至少一个资源,但又提出了新的资源要求,而该资源又被其他进程占有,请求进程阻塞,但对已经获得的资源不释放。

c) 不剥夺条件 :进程已获得的资源,使用完之前不能被剥夺,只能用完自己释放。

d) 环路等待条件 :发生死锁时,必然存在进程—资源的环形链。

10.6.3 处理死锁的基本方法

(1) 预防死锁:设置某些限制条件,破坏四个必要条件(除第一个互斥条件外的其他条件)中的一个或几个。

优点:容易实现。

缺点:系统资源利用率和吞吐量降低。

(2) 避免死锁:在资源的动态分配过程用某种方法防止系统进入不安全状态。

优点:较弱限制条件可获得较高系统资源利用率和吞吐量。

缺点:有一定实现难度。

(3) 检测死锁:预先不采取任何限制,也不检查系统是否已进入不安全区,通过设置检测机构,检测出死锁后解除。

(4) 解除死锁:常用撤消或挂起一些进程,回收一些资源。

10.7 线程间的同步和互斥

​ 为使系统中的多线程能有条不紊的运行,系统必须提供用于实现线程间同步和互斥的机制。在多线程OS中,通常提供多种同步机制:

10.7.1 互斥锁

▪ 互斥锁可以有两种状态, 即开锁(unlock)和关锁(lock)状态

▪ 对互斥量进行加锁以后,任何其他试图再次对互斥量加锁的线程都会被阻塞直到当前线程释放该互斥锁。

▪ Linux中的线程互斥锁

- int pthread_mutex_lock(pthread_mutex_t *mutex);

//返回时,互斥锁已被锁定。该线程使互斥锁锁住。如果互斥锁已被另一个线程锁定和拥有,则该线程将阻塞,直到互斥锁变为可用为止。

- int pthread_mutex_unlock(pthread_mutex_t *mutex);

//释放互斥锁,与pthread_mutex_lock成对存在。

10.7.2 条件变量

▪ 单纯的互斥锁用于短期锁定,主要是用来保证对临界区的互斥进入。而条件变量则用于线程的长期等待, 直至所等待的资源成为可用的。

▪ 使用步骤:

- 线程首先对mutex执行关锁操作,若成功便进入临界区,然后查找用于描述资源状态的数据结构,以了解资源的情况。

- 只要发现所需资源R正处于忙碌状态,线程便转为等待状态,并对mutex执行开锁操作后,等待该资源被释放;

- 若资源处于空闲状态,表明线程可以使用该资源,于是将该资源设置为忙碌状态,再对mutex执行开锁操作。

10.7.3 信号量机制

(1) 私用信号量

​ 当某线程需利用信号量来实现同一进程中各线程之间的同步时,可调用创建信号量的命令来创建一私用信号量,其数据结构存放在应用程序的地址空间中。

(2) 公用信号量

​ 公用信号量是为实现不同进程间或不同进程中各线程之间的同步而设置的。

10.8 Linux下的多线程编程

10.8.1 Linux下的多线程编程

(1) 多线程编程实例

#include <stdio.h>
#include <pthread.h>
void thread(void)
{
int i;
for(i=0;i<3;i++)
printf(“This is a pthread.\n”);
}

int main(void)
{
pthread_t id;
int i,ret;
ret=pthread_create(&id,NULL,(void *) thread,NULL);
if(ret!=0){
printf (“Create pthread error!\n”);
exit (1);
}
for(i=0;i<3;i++)
printf(“This is the main process.\n”);
pthread_join(id,NULL);
return (0);
}

执行:gcc example.c -lpthread -o example

-l参数用于指定编译时要用到的库

(2) 线程标识符 pthread_t

用来标识一个线程。

(3) 线程创建函数pthread_create

函数原型:

int pthread_create (pthread_t * thread_id, __const pthread_attr_t * __attr, void (__start_routine) (void *),void *__restrict __arg)

- 第一个参数为指向线程标识符的指针

- 第二个参数用来设置线程属性

- 第三个参数是线程运行函数的起始地址

- 最后一个参数是运行函数的参数

- 函数thread不需要参数,所以最后一个参数设为空指针。第二个参数也设为空指针,这样将生成默认属性的线程。

- 当创建线程成功时,函数返回0,若不为0则说明创建线程失败,常见的错误返回代码为EAGAIN和EINVAL。前者表示系统限制创建新的线程,例如线程数目过多了;后者表示第二个参数代表的线程属性值非法。

(4) pthread_join函数

函数原型:

int pthread_join (pthread_t __th, void **__thread_return)

- 第一个参数为被等待的线程标识符 。

- 第二个参数为一个用户定义的指针,用来存储被等待线程返回值。

- 这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源被收回。

(5) pthread_exit函数

函数原型:

void pthread_exit (void *__retval)

- 唯一的参数是函数的返回代码 。如果pthread_join中的第二个参数thread_return不是NULL,这个值将被传递给 thread_return。

- 需要注意的是:一个线程不能被多个线程等待,否则第一个接收到信号的线程成功返回,其余调用pthread_join的线程则返回错误代码ESRCH。

(6) 互斥锁

互斥锁用来保证一段时间内只有一个线程在执行一段代码。

重点

(1)线程清理机制;2)线程的属性。

这部分内容采用示例程序展示的方式教学,通过针对性的编写示例程序展示这些函数的使用,以及相应功能的实现。同时通过实验强化这部分知识的掌握。

难点

Linux多线程编程。

习题

1.比较线程和进程的区别。

答:(1) 调度

在传统的操作系统中,进程作为拥有资源和独立调度、分派的基本单位。而在引入线程的操作系统中,则把线程作为调度和分派的基本单位,而进程作为资源拥有的基本单位。

(2) 并发性

在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间亦可并发执行,使得操作系统具有更好的并发性,从而能更加有效地提高系统资源的利用率和系统的吞吐量。

(3) 拥有资源

一般而言,线程自己不拥有系统资源(也有一点必不可少的资源),但它可以访问其隶属进程的资源,即一个进程的代码段、数据段及所拥有的系统资源,如已打开的文件、I/O 设备等,可以供该进程中的所有线程所共享。

(4) 独立性

同一进程中的不同线程共享进程的内存空间和资源。

同一进程中的不同线程的独立性低于不同进程。

(5) 系统开销

线程的切换只需要保存和设置少量的寄存器内容,不涉及存储器管理方面的操作。

(6) 支持多处理机系统

一个进程分为多个线程分配到多个处理机上并行执行,可加速进程的完成。

2.死锁产生的主要原因有哪些?

答:a) 竞争不可抢占性资源引起死锁

b) 竞争临时性(消耗性)资源引起进行死锁

c) 进程推进顺序不当引起死锁

3.死锁的必要条件有哪些?

答:a) 互斥条件

b) 请求和保持条件

c) 不剥夺条件

d) 环路等待条件

  1. 如何解决死锁?

答:(1) 预防死锁:设置某些限制条件,破坏四个必要条件(除第一个互斥条件外的其他条件)中的一个或几个。

(2) 避免死锁:在资源的动态分配过程用某种方法防止系统进入不安全状态。

(3) 检测死锁:预先不采取任何限制,也不检查系统是否已进入不安全区,通过设置检测机构,检测出死锁后解除。

(4) 解除死锁:常用撤消或挂起一些进程,回收一些资源。

原创声明

=======

作者: [ libin9iOak ]


本文为原创文章,版权归作者所有。未经许可,禁止转载、复制或引用。

作者保证信息真实可靠,但不对准确性和完整性承担责任。

未经许可,禁止商业用途。

如有疑问或建议,请联系作者。

感谢您的支持与尊重。

点击下方名片,加入IT技术核心学习团队。一起探索科技的未来,共同成长。

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

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

相关文章

arcgis-elasticsearch矢量数据导入及索引设计工具

插件说明 插件支持单图层导入和多图层同时导入&#xff0c;依赖elasticsearch包和urlLib包&#xff0c;使用之前请用pip安装&#xff0c;具体的依赖包的requirements.txt文件放在压缩包里面了。 pip install -r requirements.txt插件下载地址&#xff1a;https://download.cs…

DocuSign:在全球电子签名市场具有巨大上涨潜力的SaaS股

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 总结 &#xff08;1&#xff09;DocuSign的核心电子签名业务还在持续增长&#xff0c;尽管在疫情后增速有所放缓&#xff0c;但第一季度的收入已经达到了6.61亿美元&#xff0c;增长率为12%。 &#xff08;2&#xff09;Do…

Linux:通过wget下载安装mysql数据库(5.7版本)

目前&#xff0c;主要使用的MySQL有5.7和8.0两个版本&#xff0c;在安装上&#xff0c;5.7和8.0版本基本一致&#xff0c;区别只在于配置root密码和远程登陆上不同。本次将以5.7版本作为对象&#xff0c;进行后续安装。 1.wget下载MySQL安装文件 下载完成&#xff0c;得到mysq…

PySpark如何输入数据到Spark中?【RDD对象】

PySpark支持多种数据的输入&#xff0c;在输入完成后&#xff0c;都会得到一个&#xff1a;RDD类的对象RDD全称为弹性分布式数据集(Resilient Distributed Datasets)&#xff0c;PySpark针对数据的处理&#xff0c;都是以RDD对象作为载体&#xff0c;即&#xff1a; •数据存储…

ansible实训-Day3(playbook的原理、结构及其基本使用)

一、前言 该篇是对ansible实训第三天内容的归纳总结&#xff0c;主要包括playbook组件的原理、结构及其基本使用方式。 二、Playbook 原理 Playbook是Ansible的核心组件之一&#xff0c;它是用于定义任务和配置的自动化脚本。 Ansible Playbook使用YAML语法编写&#xff0c;可…

Linux 学习记录42(C++篇)

Linux 学习记录42(C篇) 本文目录 Linux 学习记录42(C篇)一、class 类1. 类中的this指针(1. this指针的格式(2. 使用this指针 2. 类中特殊的成员函数(1. 构造函数>1 格式/定义>2 调用构造函数的时机>3 构造函数的初始化列表 (2. 析构函数>1 功能/格式>2 析构函数…

Redis的数据复制到另一台Redis

Redis的数据复制到另一台Redis 最近用到一个问题&#xff0c;需要把Redis的数据复制到另一台Redis&#xff0c;现在总结下解决问题的方法 解决方法一&#xff1a; redis-dump导出 [root ~]# redis-dump -u :password172.20.0.1:6379 > 172.20.0.1.jsonredis-load导入 [ro…

快速打造属于你的接口自动化测试框架

目录 1 接口测试 2 框架选型​​​​​​​ 3 环境搭建 4 需求 5 整体实现架构 6 RF用例实现​​​​​​​ 7 集成到CICD流程 总结&#xff1a; 1 接口测试 接口测试是对系统或组件之间的接口进行测试&#xff0c;主要是校验数据的交换&#xff0c;传递和控制管理过程…

Redis 高可用 RDB AOF

---------------------- Redis 高可用 ---------------------------------------- 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%、99.99%、99.999%等等&#xff09;。 但是在Redis语境…

基于Java人力资源管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

webassembly简单Demo——hello world

参考官网 Emscripten Tutorial 一、创建C/C文件 hello.c #include <stdio.h>int main() {printf("hello, world!\n");return 0; } 二、编译成html 命令行切到hello.c目录下&#xff0c;执行如下命令(注意需要em的环境变量&#xff0c;参考&#xff1a;emsr…

5G AI MEC智能制造数字化工业互联网大数据平台建设方案PPT

导读&#xff1a;原文《102页新一代数字化转型信息化总体规划方案PPT》共102页PPT&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 完整版领取方式 完整版领取方式&…

ARM-进入和退出异常中断的过程(六)

文章目录 ARM 处理器对异常中断的响应过程从异常中断处理程序中返回 ARM 处理器对异常中断的响应过程 ARM 指令为三级流水线&#xff1a;取地&#xff0c;译码和执行 进入中断的时候 LR PC -4 当出现异常时&#xff0c;ARM 内核自动执行以下操作 将 cpsr 寄存器的值保存到…

走近JDK 17,探索最新Java特性,拥抱未来编程!

大家好&#xff0c;我是小米&#xff0c;一个热爱技术分享的程序员。今天&#xff0c;我将为大家介绍一下JDK 17的新特性。JDK 17是Java开发工具包的一个重要版本&#xff0c;其中包含了许多令人激动的新功能和改进。在这篇文章中&#xff0c;我将详细介绍JDK 17中的各项特性&a…

Mathtype7Mac苹果ios简体中文版

对于很多人来说&#xff0c;每次编辑文字的时候遇到公式简直就是噩梦。像那些复杂的数学、物理还有化学公式&#xff0c;太难编辑出来了。 那么我们该怎么解决这些难题呢&#xff1f;其实很简单&#xff0c;用公式编辑器就行了。 公式编辑器&#xff0c;是一种工具软件&#…

前端开发爬虫首选puppeteer

很多前端同学可能对于爬虫不是很感冒&#xff0c;觉得爬虫需要用偏后端的语言&#xff0c;诸如 python 、php 等。当然这是在 nodejs 前了&#xff0c;nodejs 的出现&#xff0c;使得 Javascript 也可以用来写爬虫了。但这是大数据时代&#xff0c;数据的需求是不分前端还是后端…

基于Java会议管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

DSP f32 q15 q31 数据格式

+ V hezkz17进数字音频系统研究开发交流答疑 f32 q15 q31 分别代表什么数据格式? 2023/6/29 17:38:47 "f32"、"q15"和"q31"是不同的数据格式表示法: f32:它代表32位浮点数。在这种表示法中,32位被用来表示带有小数点的实数。其中,1位用于…

MySQL阿里巴巴规约

MySQL阿里巴巴规约 1.MySQL阿里巴巴规约【转载】 1.MySQL阿里巴巴规约【转载】

一步一步学OAK之十一:实现在RGB相机上进行对象跟踪

目录 Setup 1: 创建文件Setup 2: 安装依赖Setup 3: 导入需要的包Setup 4:定义和加载模型相关的路径和标签Setup 5: 创建pipelineSetup 6: 创建节点Setup 7: 设置属性设置相机属性设置神经网络节点属性设置物体跟踪对象属性 Setup 8: 建立链接Setup 9: 连接设备并启动管道Setup …