RTT(RT-Thread)线程间同步(保姆级)

news2024/12/23 17:14:00

目录

线程间同步

信号量

信号量结构体

信号量的使用和管理

动态创建信号量

实例

静态创建信号量

初始化和脱离信号量

获取信号量

信号量的互斥操作

获取信号量函数

释放信号量

信号量同步实例

互斥量(互斥锁)

互斥量的使用和管理

动态创建互斥量

动态创建过程

静态创建互斥量

静态创建过程

获取互斥量

释放互斥量

互斥锁实例

事件集

动态创建事件集

创建和删除

静态创建事件集

初始化和脱离

事件集创建过程

事件集实现线程同步

发送事件

接收事件

实现原理

实现过程

事件集实现进程同步源码


 

线程间同步

        多个执行单元(线程、中断)同时执行临界区(多个执行单元会同时执行到的代码区域),操作临界资源,会导致竟态产生,为了解决这种竟态问题,RT-Thread OS提供了如下几种同步互斥机制:

  • 信号量
  • 互斥量
  • 事件集

同步的概念是:多个执行单元执行临界区的时候按照顺序的方式执行

互斥的概念:互斥强调的是排他性,比如有两个线程A和B。当线程A执行的时候,线程B不能执行;线程B执行的时候,线程A不能执行。只有当一个线程执行完之后,另一个线程才能执行。

信号量

        信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步互斥的目的。

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

信号量结构体

当信号量被使用,value的值减1;当信号量被释放,value值加1

struct rt_semaphore
{
   struct rt_ipc_object parent; /**< inherit from ipc_object  继承自ipc_object类*/

   rt_uint16_t          value;       /**< value of semaphore. */
   rt_uint16_t         reserved;    /**< reservedfield 预留*/ 
};typedef struct
rt_semaphore *rt_sem_t;

信号量的使用和管理

        对一个信号量的操作包含:创建 /初始化信号量、获取信号量、释放信号量、删除 / 脱离信号量。

        创建完信号量之后,需要找到临界区,在临界区之前获取信号量,在临界区之后要释放信号量。

动态创建信号量

参数1:信号量名字

参数2:信号量资源个数

参数3:#define RT_IPC_FLAG_FIFO 0x00 //按照线程先进先出获取信号量资源

             #define RT_IPC_FLAG_PRIO 0x01 //按照线程优先级获取信号量资源

返回值为信号量结构体指针

/**
 * This function will create a semaphore from system resource
 *
 * @param name the name of semaphore
 * @param value the initial value of semaphore
 * @param flag the flag of semaphore
 *
 * @return the created semaphore, RT_NULL on error happen
 *
 * @see rt_sem_init
 */
rt_sem_t rt_sem_create(const char *name, rt_uint32_t value, rt_uint8_t flag)

系统不再使用信号量时,可通过删除信号量以释放系统资源,适用于动态创建的信号量。

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

/**
 * This function will delete a semaphore objectand release the memory
 *
 * @param sem the semaphore object
 *
 * @return the error code
 *
 * @see rt_sem_detach
 */
rt_err_t rt_sem_delete(rt_sem_t sem)
实例

semaphore为信号量的名字,V为信号量的当前资源数,suspend thread为挂载在信号量上的线程数。但发现信号量名字少了最后面的“1”

注意名字设置的时候,必须要小于等于8个字符

静态创建信号量

初始化和脱离信号量
/**
 * This function will initialize a semaphoreand put it under control of
 * resource management.
 *
 * @param sem the semaphore object
 * @param name the name of semaphore
 * @param value the initial value of semaphore
 * @param flag the flag of semaphore
 *
 * @return the operation status, RT_EOK onsuccessful
 */
rt_err_t rt_sem_init(rt_sem_t    sem,
                     const char *name,
                     rt_uint32_t value,
                     rt_uint8_t  flag)

脱离信号量就是让信号量对象从内核对象管理器中脱离,适用于静态初始化的信号量,

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

/**
 * This function will detach a semaphore from resource management
 *
 * @param sem the semaphore object
 *
 * @return the operation status, RT_EOK on successful
 *
 * @see rt_sem_delete
 */
rt_err_t rt_sem_detach(rt_sem_t sem)

 

 

获取信号量

        线程通过获取信号量来获得信号量资源实例,当信号量值大于零时,线程将获得信号量,并且相应的信号量值会减 1,如果信号量的值等于零,那么说明当前信号量资源实例不可用,申请该信号量的线程将根据time参数的情况选择直接返回、或挂起等待一段时间、或永久等待,直到其他线程或中断释放该信号量。如果在参数time指定的时间内依然得不到信号量,线程将超时返回,返回值是 - RT_ETIMEOUT。

        比如说现在有线程1和线程2两个线程同时都能执行临界区的代码,在临界区存在一个临界资源变量i。此时线程1和线程2是存在竞态关系的,我们可以通过信号量来阻止竞态的发生。

        我们将信号量的value设置为1,在进入临界区之前,我们先获取信号量,在出临界区的时候再释放信号量。那么不管是线程1还是线程2,谁先执行临界区,都会先获取信号量,然后信号量value减1,变成0;此时线程2发现信号量value为0,就会选择休眠。直到线程1释放掉信号量,value值加1,就会唤醒线程2。那么线程2就会获取到信号量,从而操作临界区。

信号量的互斥操作

不管是谁先进入临界区操作临界区的资源,其它的线程就没办法来操作;只有等到操作完临界区的线程释放资源,其它的线程才能进行操作;每一个时刻只有一个线程可以操作临界区。

获取信号量函数

第一个参数为信号量的结构体指针

第二个参数为time,我们通过time可以知道如果线程获取不到信号量的时候是处于什么样的状态(如果为RT_WAITING_FOREVER就进入休眠状态一直等待信号量;RT_WAITING_NO为非阻塞的模式,如果线程获取不到信号量就直接返回,不会休眠;再然后其它的time值就是自己设置的等待时间:注意时间要大于0)

释放信号量

释放信号量可以唤醒挂起在该信号量上的线程

/**
 * This function will release a semaphore, ifthere are threads suspended on
 * semaphore, it will be waked up.
 *
 * @param sem the semaphore object
 *
 * @return the error code
 */
rt_err_t rt_sem_release(rt_sem_t sem)

信号量同步实例

(1)首先创建一个全局变量flags

(2)然后创建两个线程,让它们都能够操作到flags(我们将线程的优先级设置为相同优先级,这样才可能会导致竞态产生)

(3)此时我们想实现线程1和线程2的同步操作,即先执行线程1然后执行线程2,顺序执行

原理:比如说我们现在有两个信号量,信号量1初始化value为1,信号量2初始化value为0。线程1进入临界空间以后首先获取信号量1(信号量value大于1,获取成功),等线程1执行完之后信号量1会自动减1,然后释放信号量2,信号量2加1;此时线程2可以获取到信号量2,开始执行,执行完之后信号量2自动减1,然后释放信号量1,信号量1加1,然后线程1又开始执行了。按照顺序依次执行。

(4)创建两个信号量sem1和sem2

(5)完善线程执行函数:线程1先休眠8秒,线程2执行完一次再休眠2秒

(6)main函数中启动两个线程

(7)实验现象

烧写程序上电后,发现两个线程都处于挂起状态

因为线程1处于8秒的延时状态,而线程2此时无法获取到信号量

运行完效果:两个线程按顺序交替操作,flags的值在0-1跳转

互斥量(互斥锁)

        互斥量体现的是排他性,也是解决多线程同时操作临界区临界资源导致的竟态的一种方法。(类似于特殊的信号量——二值信号量)

        区别:信号量可由不同线程释放,互斥量只能由同一线程进行释放。

互斥量的使用和管理

互斥量的操作包含:创建 / 初始化互斥量、获取互斥量(相对于上锁)、释放互斥量(相对于解锁)、删除 / 脱离互斥量

动态创建互斥量

rt_mutex_create函数用于创建互斥量

参数1:信号量名字

参数2:#define RT_IPC_FLAG_FIFO 0x00 //按照线程先进先出获取信号量资源

             #define RT_IPC_FLAG_PRIO 0x01 //按照线程优先级获取信号量资源

返回值为结构体指针变量rt_mutex_t

#ifdef RT_USING_HEAP
/**
 * This function will create a mutex from system resource
 *
 * @param name the name of mutex
 * @param flag the flag of mutex
 *
 * @return the created mutex, RT_NULL on error happen
 *
 * @see rt_mutex_init
 */
rt_mutex_t rt_mutex_create(const char *name, rt_uint8_t flag)

不再使用互斥量时,通过删除互斥量以释放系统资源,适用于动态创建的互斥量

当删除一个互斥量时,所有等待此互斥量的线程都将被唤醒,等待线程获得的返回值是

- RT_ERROR

/**
 * This function will delete a mutex object andrelease the memory
 *
 * @param mutex the mutex object
 *
 * @return the error code
 *
 * @see rt_mutex_detach
 */
rt_err_t rt_mutex_delete(rt_mutex_t mutex)
动态创建过程

静态创建互斥量

初始化和脱离互斥量

注意传入的第一个参数是结构体变量的地址

/**
 * This function will initialize a mutex andput it under control of resource
 * management.
 *
 * @param mutex the mutex object
 * @param name the name of mutex
 * @param flag the flag of mutex
 *
 * @return the operation status, RT_EOK onsuccessful
 */
rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag)

使用该函数接口后,内核先唤醒所有挂在该互斥量上的线程(线程的返回值是

-RT_ERROR) ,然后系统将该互斥量从内核对象管理器中脱离。

/**
 * This function will detach a mutex fromresource management
 *
 * @param mutex the mutex object
 *
 * @return the operation status, RT_EOK onsuccessful
 *
 * @see rt_mutex_delete
 */
rt_err_t rt_mutex_detach(rt_mutex_t mutex)
静态创建过程

一般创建好互斥锁,是不会去删除或者分离的,如果要删除则分别使用delete和detach

获取互斥量

/**
 * This function will take a mutex, if themutex is unavailable, the
 * thread shall wait for a specified time.
 *
 * @param mutex the mutex object
 * @param time the waiting time
 *
 * @return the error code
 */
rt_err_t rt_mutex_take(rt_mutex_tmutex, rt_int32_t time)

释放互斥量

/**
 * This function will release a mutex, if thereare threads suspended on mutex,
 * it will be waked up.
 *
 * @param mutex the mutex object
 *
 * @return the error code
 */
rt_err_t rt_mutex_release(rt_mutex_tmutex)

互斥锁实例

(1)首先创建两个临界资源flag1和flag2

(2)创建一个互斥锁

(3)创建两个线程

(4)在如下的情况下我们可以发现运行时,每次打印出来的flag1和flag2的值是不相等的

如果我们想要实现每次打印的两个值相等,则要确保线程1执行完成一次循环之后再执行线程2(即线程不会因为休眠挂起而被另一个线程操作临界区资源)。我们将线程1的while(1)设为临界区,进行上锁

(5)为相应临界区上锁和解锁

(6)结果现象

从输出的实验结果可以得知如果有两个线程使用同一把锁,则线程B必须等线程A执行完上锁和解锁及临界区的操作,才可以执行上锁操作,并继续往下执行,否则上锁失败,线程B就会进入挂起状态等待线程A解锁方可唤醒

事件集

        事件集也是线程间同步的机制之一,一个事件集可以包含多个事件,利用事件集可以完成一对多,多对多的线程间同步。

一个线程和多个事件的关系可设置为:

        其中任意一个事件唤醒 线程,或几个事件都到达后唤醒线程,多个事件集合可以用一个32bit无符号整型变量来表示,变量的每一位代表一个事件,线程通过"逻辑与"或"逻辑或"将一个或多个事件关联起来,形成事件组合。

RT-Thread 定义的事件集有以下特点:

  • 事件只与线程相关,事件间相互独立
  • 事件仅用于同步,不提供数据传输功能
  • 事件无排队性,即多次向线程发送同一事件(如果线程还未来得及读走),其效果等同于只发送一次

动态创建事件集

创建和删除

/*
 * event structure
 */
struct rt_event
{
   struct rt_ipc_object parent;     /**< inherit from ipc_object */

   rt_uint32_t          set;         /**< event set */
};
typedef struct rt_event *rt_event_t;

/**
 * This function will create an event objectfrom system resource
 *
 * @param name the name of event
 * @param flag the flag of eventRT_IPC_FLAG_FIFO RT_IPC_FLAG_PRIO
 *
 * @return the created event, RT_NULL on errorhappen
 */
rt_event_t rt_event_create(const char*name, rt_uint8_t flag)
/**
 * This function will delete an event objectand release the memory
 *
 * @param event the event object
 *
 * @return the error code
 */
rt_err_t rt_event_delete(rt_event_tevent)

静态创建事件集

初始化和脱离

/**
 * This function will initialize an event andput it under control of resource
 * management.
 *
 * @param event the event object
 * @param name the name of event
 * @param flag the flag of event
 *
 * @return the operation status, RT_EOK onsuccessful
 */
rt_err_t rt_event_init(rt_event_tevent, const char *name, rt_uint8_t flag)
/**
 * This function will detach an event objectfrom resource management
 *
 * @param event the event object
 *
 * @return the operation status, RT_EOK onsuccessful
 */
rt_err_t rt_event_detach(rt_event_tevent)

事件集创建过程

(与前面类似,这里以动态为例)

事件集实现线程同步

事件集有多个事件,能够完成多个事件的同步。之前在完成线程同步的时候用的是信号量,但用到的是多个信号量才能完成线程的同步。而现在我们可以通过一个事件集来完成线程的同步。

事件集用的集合的类型是无符号32bit整形,事件的占位是一个事件占用一个位。所以一个集合里面支持32个事件。

发送事件

该函数给事件集对象发送一个事件,如果存在线程在事件集对象上挂起,它将会被唤醒

第一个参数为事件的结构体指针(事件集对象)

第二个参数为具体的事件值

/**
 * This function will send an event to the event object, if there are threads
 * suspended on event object, it will be wakedup.
 *
 * @param event the event object
 * @param set the event set
 *
 * @return the error code
 */
rt_err_t rt_event_send(rt_event_tevent, rt_uint32_t set)

接收事件

该函数的功能是从事件集对象里面接收一个事件,如果事件是不可用的,线程将进入休眠(挂起状态)

第二个参数为指定具体接收是哪个事件

第三个参数为接收的操作,设置与和或的关系,还有是否设置在接收完某个事件后对位进行清除

第四个参数设置等待时间,与前面相同

第五个参数用于接收事件的值,如果不关心就不设置

/**
 * This function will receive an event from event object, if the event is
 * unavailable, the thread shall wait for aspecified time.
 *
 * @param event the fast event object
 * @param set the interested event set
 * @param option the receive option, eitherRT_EVENT_FLAG_AND or
 *       RT_EVENT_FLAG_OR should be set. RT_EVENT_FLAG_CLEAR 
 * @param timeout the waiting time  RT_WAITING_FOREVER RT_WAITING_NO
 * @param recved the received event, if youdon't care, RT_NULL can be set.
 *
 * @return the error code
 */
rt_err_trt_event_recv(rt_event_t   event,
                       rt_uint32_t  set,
                       rt_uint8_t   option,
                       rt_int32_t   timeout,
                       rt_uint32_t *recved)

实现原理

我们要用事件集实现三个线程的同步

如果采用信号量的话,我们需要三个信号。而采用事件集,我们只要使用三个事件位即可。

以事件2为例,当调度器调度到线程2,此时发现线程2没有接收到事件2,就无法往下执行,它就会挂起,从而线程3也无法接收到事件3。因此我们可以手动在main函数中手动发送一个事件,从而触发一个线程可以正常执行。

我们再使用事件集的时候,还可以用到or和and的关系。and:比如可以设置事件1和事件2同时满足的,线程1才可以执行;or:比如设置事件1或事件2有一个满足,线程1就可以执行

实现过程

(1)创建事件集

(3)创建三个线程

(4)发送、接收事件使用

在main中手动发送

(5)实验效果:每秒钟按照1、2、3的顺序执行

事件集实现进程同步源码

#include <rtthread.h>

#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

rt_event_t event1;
rt_thread_t th1,th2,th3;

#define EVENT_FLAGS_1 (0x01<<0)
#define EVENT_FLAGS_2 (0x01<<1)
#define EVENT_FLAGS_3 (0x01<<2)
void th1_entry(void *parameter)
{
    while(1){
        rt_event_recv(event1,EVNET_FLAGS_1,RT_EVENT_FLAG_CLEAR | RT_EVENT_FLAG_AND,\
                RT_WAITING_FOREVER,NULL);
        rt_kprintf("th1_entry...\n");
        rt_event_send(event1,EVENT_FLAGS_2);
        rt_thread_mdelay(1000);
    }
}
void th2_entry(void *parameter)
{
    while(1){
        rt_event_recv(event1,EVNET_FLAGS_2,RT_EVENT_FLAG_CLEAR | RT_EVENT_FLAG_AND,\
                        RT_WAITING_FOREVER,NULL);
        rt_kprintf("th2_entry...\n");
        rt_event_send(event1,EVENT_FLAGS_3);
        rt_thread_mdelay(1000);
    }
}
void th3_entry(void *parameter)
{
    while(1){
        rt_event_recv(event1,EVNET_FLAGS_3,RT_EVENT_FLAG_CLEAR | RT_EVENT_FLAG_AND,\
                                RT_WAITING_FOREVER,NULL);
        rt_kprintf("th3_entry...\n");
        rt_event_send(event1,EVENT_FLAGS_1);
        rt_thread_mdelay(1000);
    }
}
int main(void)
{

    event1 = rt_event_create("set1", RT_IPC_FLAG_FIFO);
    if(event1 == RT_NULL)
    {
        LOG_E("rt_event_create failed...\n");
        return -ENOMEM;
    }
    LOG_D("rt_event_create succeed...\n");
    th1 = rt_thread_create("th1",th1_entry,RT_NULL,512,10,5);
    if(th1 == RT_NULL){
        LOG_E("th1 rt_thread_create failed...\n");
        return -ENOMEM;
    }
    th2 = rt_thread_create("th2",th2_entry,RT_NULL,512,10,5);
    if(th2 == RT_NULL){
        LOG_E("th2 rt_thread_create failed...\n");
        return -ENOMEM;
    }
    th3 = rt_thread_create("th3",th3_entry,RT_NULL,512,10,5);
    if(th3 == RT_NULL){
        LOG_E("th3 rt_thread_create failed...\n");
        return -ENOMEM;
    }
    rt_thread_startup(th1);
    rt_thread_startup(th3);
    rt_thread_startup(th2);
    
    rt_event_send(event1,EVENT_FLAGS_1);
    return RT_EOK;
}

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

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

相关文章

【nacos】Param ‘serviceName‘ is illegal, serviceName is blank

报错信息 解决方式 一&#xff1a;缺少依赖 SpringBoot2.4之后不会默认加载bootstrap.yaml&#xff1b;需要手动在pom中加入如下依赖&#xff1a; <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-boot…

SCAU操作系统知识点之(一)计算机系统概述

缩写词&#xff1a; OS: Operating System 操作系统 PSW: Program Status Word 程序状态字 FCFS: First Come First Serve 先来先服务 PCB: Process Control Block 进程控制块 DMA: Direct Memory Access 直接存储器存取 MMU: Memory Management Unit 内存管理单元 SSTF: Short…

【maven】通过profiles实现:怎样激活某个仓库、同时加载多个profile、不同环境加载不同依赖jar

文章目录 一. 基本用法二. 仓库激活方式1. 使用activeProfile激活2. 使用-P参数激活3. 使用-P参数不激活 三. 查看激活的仓库四. 不同环境依赖不同版本的jar Maven中的profile是一组可选的配置&#xff0c;可以用来设置或者覆盖配置默认值。有了profile&#xff0c;你就可以为不…

(el-Form)操作(不使用 ts):Element-plus 中 Form 表单组件校验规则等的使用

Ⅰ、Element-plus 提供的 Form 表单组件与想要目标情况的对比&#xff1a; 1、Element-plus 提供 Form 表单组件情况&#xff1a; 其一、Element-plus 自提供的 Form 代码情况为(示例的代码)&#xff1a; // Element-plus 自提供的代码&#xff1a; // 此时是使用了 ts 语言环…

(JS逆向专栏十四)某游平台网站登入SHA1

声明: 本文章中所有内容仅供学习交流&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01; 名称:逗游 目标:登入参数 加密类型:SHA1 目标网址:https://www.doyo.cn/passport/l…

HTML+JavaScript构建一个将C/C++定义的ANSI字符串转换为MASM32定义的DWUniCode字符串的工具

公文一键排版系统基本完成&#xff0c;准备继续完善SysInfo&#xff0c;增加用户帐户信息&#xff0c;其中涉及到Win32_Account结构&#xff0c;其C定义如下&#xff1a; [Dynamic, Provider("CIMWin32"), UUID("{8502C4CC-5FBB-11D2-AAC1-006008C78BC7}"…

SpringBoot整合、SpringBoot与异步任务

目录 一、背景描述二、简单使用方法三、原理五、使用自定义线程池六、Async失效情况 一、背景描述 java 的代码是同步顺序执行&#xff0c;当我们需要执行异步操作时我们通常会去创建一个新线程去执行。比如new Thread()。start()&#xff0c;或者使用线程池线程池 new Thread…

Rust 编程小技巧摘选(6)

目录 Rust 编程小技巧(6) 1. 打印字符串 2. 重复打印字串 3. 自定义函数 4. 遍历动态数组 5. 遍历二维数组 6. 同时遍历索引和值 7. 检查数组是否包含某个值 8. 二维矩阵中查找某个值 附&#xff1a;迭代器方法的区别 Rust 编程小技巧(6) 1. 打印字符串 fn main() …

案例10 Maven入门案例

基于Maven构建快速构建项目&#xff0c;输出“Hello World&#xff01;”。 1.选择Maven快速构建项目 ​2.设置Maven项目信息 ​3.设置Maven环境信息 ​4.项目结构 ​ 5.Maven操作 ​6.执行结果

Android图形-合成与显示-SurfaceTestDemo

目录 引言&#xff1a; 主程序代码&#xff1a; 结果呈现&#xff1a; 小结&#xff1a; 引言&#xff1a; 通过一个最简单的测试程序直观Android系统的native层Surface的渲染显示过程。 主程序代码&#xff1a; #include <cutils/memory.h> #include <utils/L…

vue左右div结构手动拉伸并且echarts图表根据拉伸宽高自适应

需求&#xff1a; 左右结构的div&#xff0c;可以根据数据抬起按下进行拉伸修改容器宽度的操作给左右结构某一图表设置拉伸自适应左右结构都设置个最小宽度&#xff0c;只能到一定区域内拉伸解决echarts的bug&#xff08;重复加载chart实例&#xff09;&#xff1a;[ECharts] …

数据通信——VRRP

引言 之前把实验做了&#xff0c;结果发现我好像没有写过VRRP的文章&#xff0c;连笔记都没记过。可能是因为对STP的记忆&#xff0c;导致现在都没忘太多。 一&#xff0c;什么是VRRP VRRP全名是虚拟路由冗余协议&#xff0c;虚拟路由&#xff0c;看名字就知道这是运行在三层接…

python接口自动化测试框架2.0,让你像Postman一样编写测试用例,支持多环境切换、多业务依赖、数据库断言等

项目介绍 接口自动化测试项目2.0 软件架构 本框架主要是基于 Python unittest ddt HTMLTestRunner log excel mysql 企业微信通知 Jenkins 实现的接口自动化框架。 前言 公司突然要求你做自动化&#xff0c;但是没有代码基础不知道怎么做&#xff1f;或者有自动化…

Fairy下载和使用

写在最前&#xff1a;本系列中将会涉及到 Unity&#xff0c;C#&#xff0c;Lua和FairyGUI&#xff08;FGUI&#xff09;。 FairyGUI介绍 官网&#xff1a; FairyGUI 编辑器下载&#xff1a; FairyGUI 截至文档记录最新版&#xff1a; https://res.fairygui.com/FairyGUI-Ed…

Exams/ece241 2013 q4

蓄水池问题 S3 S2 S1 例如&#xff1a;000 代表 无水 &#xff0c;需要使FR3, FR2, FR1 都打开&#xff08;111&#xff09; S3 S2 S1 FR3 FR2 FR1 000 111 001 011 011 001 111 000 fr代表水变深为…

Eleastisearch5.2.2利用镜像迁移构建实例后ES非健康状态

正常迁移完成后启动服务&#xff0c;查看ES非健康状态 此时观察ES集群状态&#xff1a;curl -XGET -u elastic:xxx localhost:9200/_cluster/health?pretty 注意到"active_shards_percent_as_number" : 88.8888 该项的值不产生变化;集群状态"status" : “…

LAXCUS如何通过技术创新管理数千台服务器

随着互联网技术的不断发展&#xff0c;服务器已经成为企业和个人获取信息、进行计算和存储的重要工具。然而&#xff0c;随着服务器数量的不断增加&#xff0c;传统的服务器管理和运维方式已经无法满足现代企业的需求。LAXCUS做为专注服务器集群的【数存算管】一体化平台&#…

JVM—内存管理(运行时数据区)、垃圾回收

背景介绍 当JVM类加载器加载完字节码文件之后&#xff0c;会交给执行引擎执行&#xff0c;在执行的过程中会有一块JVM内存区域来存放程序运行过程中的数据&#xff0c;也就是我们图中放的运行时数据区&#xff0c;那这一块运行时数据区究竟帮我们做了哪些工作&#xff1f;我们…

【学习FreeRTOS】第6章——FreeRTOS中断管理

【本篇文章的也可参考STM32中断文章http://t.csdn.cn/foF9I&#xff0c;结合着学习效果更好】 1.什么是中断 中断&#xff1a;让CPU打断正常运行的程序&#xff0c;转而去处理紧急的事件&#xff08;程序&#xff09;&#xff0c;就叫中断中断执行机制&#xff0c;可简单概括…