rtt设备驱动框架学习——内核对象基类object

news2024/10/6 3:33:59

内核对象基类object

这个基类是内核所有对象的基类

在rt-thread/include/rtdef.h文件里有对内核对象基类object的定义

/**
 * Base structure of Kernel object
 */
struct rt_object
{
    char       name[RT_NAME_MAX];                       /**< name of kernel object */
    rt_uint8_t type;                                    /**< type of kernel object */
    rt_uint8_t flag;                                    /**< flag of kernel object */

#ifdef RT_USING_MODULE
    void      *module_id;                               /**< id of application module */
#endif
    rt_list_t  list;                                    /**< list node of kernel object */
};
typedef struct rt_object *rt_object_t;                  /**< Type for kernel objects. */

object属性有 内核对象名字 , 内核对象类型 , 内核对象标志,还有一个链表节点。

内核对象信息结构体

/**
 * The information of the kernel object
 */
struct rt_object_information
{
    enum rt_object_class_type type;                     /**< object class type */
    rt_list_t                 object_list;              /**< object list */
    rt_size_t                 object_size;              /**< object size */
};

其中rt_object_class_type是一个枚举类型,定义如下

/**
 *  The object type can be one of the follows with specific
 *  macros enabled:
 *  - Thread
 *  - Semaphore
 *  - Mutex
 *  - Event
 *  - MailBox
 *  - MessageQueue
 *  - MemHeap
 *  - MemPool
 *  - Device
 *  - Timer
 *  - Module
 *  - Unknown
 *  - Static
 */
enum rt_object_class_type
{
    RT_Object_Class_Null          = 0x00,      /**< The object is not used. */
    RT_Object_Class_Thread        = 0x01,      /**< The object is a thread. */
    RT_Object_Class_Semaphore     = 0x02,      /**< The object is a semaphore. */
    RT_Object_Class_Mutex         = 0x03,      /**< The object is a mutex. */
    RT_Object_Class_Event         = 0x04,      /**< The object is a event. */
    RT_Object_Class_MailBox       = 0x05,      /**< The object is a mail box. */
    RT_Object_Class_MessageQueue  = 0x06,      /**< The object is a message queue. */
    RT_Object_Class_MemHeap       = 0x07,      /**< The object is a memory heap. */
    RT_Object_Class_MemPool       = 0x08,      /**< The object is a memory pool. */
    RT_Object_Class_Device        = 0x09,      /**< The object is a device. */
    RT_Object_Class_Timer         = 0x0a,      /**< The object is a timer. */
    RT_Object_Class_Module        = 0x0b,      /**< The object is a module. */
    RT_Object_Class_Memory        = 0x0c,      /**< The object is a memory. */
    RT_Object_Class_Unknown       = 0x0e,      /**< The object is unknown. */
    RT_Object_Class_Static        = 0x80       /**< The object is a static object. */
};

有我们常见的线程,信号量等等,最后一个静态类型 就是 第一位 置1。
这里我们只关注 设备类 ,也就是 RT_Object_Class_Device

它们之间具体是个什么关系呢
具体我们来看rt-thread/src/object.c文件

对象容器

对象容器就是一个rt_object_information类型的数组,数组名_object_container,数组长度为RT_Object_Info_Unknown,这个数组中的每个值都是rt_object_information类型。

static struct rt_object_information _object_container[RT_Object_Info_Unknown] =
{
    /* initialize object container - thread */
    {RT_Object_Class_Thread, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Thread), sizeof(struct rt_thread)},
#ifdef RT_USING_SEMAPHORE
    /* initialize object container - semaphore */
    {RT_Object_Class_Semaphore, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Semaphore), sizeof(struct rt_semaphore)},
#endif
#ifdef RT_USING_MUTEX
    /* initialize object container - mutex */
    {RT_Object_Class_Mutex, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Mutex), sizeof(struct rt_mutex)},
#endif
#ifdef RT_USING_EVENT
    /* initialize object container - event */
    {RT_Object_Class_Event, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Event), sizeof(struct rt_event)},
#endif
#ifdef RT_USING_MAILBOX
    /* initialize object container - mailbox */
    {RT_Object_Class_MailBox, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MailBox), sizeof(struct rt_mailbox)},
#endif
#ifdef RT_USING_MESSAGEQUEUE
    /* initialize object container - message queue */
    {RT_Object_Class_MessageQueue, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MessageQueue), sizeof(struct rt_messagequeue)},
#endif
#ifdef RT_USING_MEMHEAP
    /* initialize object container - memory heap */
    {RT_Object_Class_MemHeap, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemHeap), sizeof(struct rt_memheap)},
#endif
#ifdef RT_USING_MEMPOOL
    /* initialize object container - memory pool */
    {RT_Object_Class_MemPool, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_MemPool), sizeof(struct rt_mempool)},
#endif
#ifdef RT_USING_DEVICE
    /* initialize object container - device */
    {RT_Object_Class_Device, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Device), sizeof(struct rt_device)},
#endif
    /* initialize object container - timer */
    {RT_Object_Class_Timer, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Timer), sizeof(struct rt_timer)},
#ifdef RT_USING_MODULE
    /* initialize object container - module */
    {RT_Object_Class_Module, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Module), sizeof(struct rt_dlmodule)},
#endif
#ifdef RT_USING_HEAP
    /* initialize object container - small memory */
    {RT_Object_Class_Memory, _OBJ_CONTAINER_LIST_INIT(RT_Object_Info_Memory), sizeof(struct rt_memory)},
#endif
};

这个容器(数组)到底有多大呢,也就是RT_Object_Info_Unknown为几呢?

还是在object.c文件中有一个枚举类型定义rt_object_info_type我们来看一下它。

/*
 * define object_info for the number of _object_container items.
 */
enum rt_object_info_type
{
    RT_Object_Info_Thread = 0,                         /**< The object is a thread. */
#ifdef RT_USING_SEMAPHORE
    RT_Object_Info_Semaphore,                          /**< The object is a semaphore. */
#endif
#ifdef RT_USING_MUTEX
    RT_Object_Info_Mutex,                              /**< The object is a mutex. */
#endif
#ifdef RT_USING_EVENT
    RT_Object_Info_Event,                              /**< The object is a event. */
#endif
#ifdef RT_USING_MAILBOX
    RT_Object_Info_MailBox,                            /**< The object is a mail box. */
#endif
#ifdef RT_USING_MESSAGEQUEUE
    RT_Object_Info_MessageQueue,                       /**< The object is a message queue. */
#endif
#ifdef RT_USING_MEMHEAP
    RT_Object_Info_MemHeap,                            /**< The object is a memory heap */
#endif
#ifdef RT_USING_MEMPOOL
    RT_Object_Info_MemPool,                            /**< The object is a memory pool. */
#endif
#ifdef RT_USING_DEVICE
    RT_Object_Info_Device,                             /**< The object is a device */
#endif
    RT_Object_Info_Timer,                              /**< The object is a timer. */
#ifdef RT_USING_MODULE
    RT_Object_Info_Module,                             /**< The object is a module. */
#endif
#ifdef RT_USING_HEAP
    RT_Object_Info_Memory,                            /**< The object is a memory. */
#endif
    RT_Object_Info_Unknown,                            /**< The object is unknown. */
};

可以看到是由宏定义决定的,宏定义在rtconfig.h文件中。
在这个枚举类型中RT_Object_Info_Thread,RT_Object_Info_Timer,RT_Object_Info_Unknown, 是必然有的。而且RT_Object_Info_Unknown放在最后一个位置。
那么我们现在定义了RT_USING_DEVICE,开启设备类。那么这个枚举类型中一共有四个元素,所以RT_Object_Info_Unknown = 3。
然后 对象容器的长度 就也为3 。里面分别有线程,定时器,还有设备的对象信息rt_object_information。
这个容器直接进行了初试化,每个元素的第二个成员也就是链表通过宏,指向本身进行初始化,也就是这个链表头(哨卫)前后都指向本身。这个链表用来链接同类的对象,后面会学习到。

#define _OBJ_CONTAINER_LIST_INIT(c)     \
    {&(_object_container[c].object_list), &(_object_container[c].object_list)}

内核对象函数

rt_object_get_information

/**
 * @brief This function will return the specified type of object information.
 *
 * @param type is the type of object, which can be
 *             RT_Object_Class_Thread/Semaphore/Mutex... etc
 *
 * @return the object type information or RT_NULL
 */
struct rt_object_information *
rt_object_get_information(enum rt_object_class_type type)
{
    int index;

    for (index = 0; index < RT_Object_Info_Unknown; index ++)
        if (_object_container[index].type == type) return &_object_container[index];

    return RT_NULL;
}

这个函数用于获取对象的类型信息,输入值是rt_object_class_type ,返回值是rt_object_information 指针。它们俩的关系是rt_object_class_type 是rt_object_information 的第一个成员。也就是说通过类型来获取这个类型的对象的具体信息(后面为了要链表)。
它是咋实现的呢。
通过遍历对象容器_object_container来实现。

rt_object_get_length

/**
 * @brief This function will return the length of object list in object container.
 *
 * @param type is the type of object, which can be
 *             RT_Object_Class_Thread/Semaphore/Mutex... etc
 *
 * @return the length of object list
 */
int rt_object_get_length(enum rt_object_class_type type)
{
    int count = 0;
    rt_ubase_t level;
    struct rt_list_node *node = RT_NULL;
    struct rt_object_information *information = RT_NULL;

    information = rt_object_get_information((enum rt_object_class_type)type);
    if (information == RT_NULL) return 0;

    level = rt_hw_interrupt_disable();
    /* get the count of objects */
    rt_list_for_each(node, &(information->object_list))
    {
        count ++;
    }
    rt_hw_interrupt_enable(level);

    return count;
}

这个函数用于获取对象链表的长度,输入值是rt_object_class_type ,也就是哪一类对象,然后获取这类对象上的链表链接的长度。
rt_list_for_each是一个宏,用来遍历链表。

/**
 * rt_list_for_each - iterate over a list
 * @pos:    the rt_list_t * to use as a loop cursor.
 * @head:   the head for your list.
 */
#define rt_list_for_each(pos, head) \
    for (pos = (head)->next; pos != (head); pos = pos->next)

具体实现:先获取类型的对象信息,对象信息里有一个链表节点,这个节点是链表头(哨卫),从次开始遍历链表,从而获取链表长度,注意这个长度是不包含哨卫的。

rt_object_get_pointers

/**
 * @brief This function will copy the object pointer of the specified type,
 *        with the maximum size specified by maxlen.
 *
 * @param type is the type of object, which can be
 *             RT_Object_Class_Thread/Semaphore/Mutex... etc
 *
 * @param pointers is the pointer will be saved to.
 *
 * @param maxlen is the maximum number of pointers can be saved.
 *
 * @return the copied number of object pointers.
 */
int rt_object_get_pointers(enum rt_object_class_type type, rt_object_t *pointers, int maxlen)
{
    int index = 0;
    rt_ubase_t level;

    struct rt_object *object;
    struct rt_list_node *node = RT_NULL;
    struct rt_object_information *information = RT_NULL;

    if (maxlen <= 0) return 0;

    information = rt_object_get_information((enum rt_object_class_type)type);
    if (information == RT_NULL) return 0;

    level = rt_hw_interrupt_disable();
    /* retrieve pointer of object */
    rt_list_for_each(node, &(information->object_list))
    {
        object = rt_list_entry(node, struct rt_object, list);

        pointers[index] = object;
        index ++;

        if (index >= maxlen) break;
    }
    rt_hw_interrupt_enable(level);

    return index;
}

rt_object_init

/**
 * @brief This function will initialize an object and add it to object system
 *        management.
 *
 * @param object is the specified object to be initialized.
 *
 * @param type is the object type.
 *
 * @param name is the object name. In system, the object's name must be unique.
 */
void rt_object_init(struct rt_object         *object,
                    enum rt_object_class_type type,
                    const char               *name)
{
    register rt_base_t temp;
    struct rt_list_node *node = RT_NULL;
    struct rt_object_information *information;
#ifdef RT_USING_MODULE
    struct rt_dlmodule *module = dlmodule_self();
#endif /* RT_USING_MODULE */

    /* get object information */
    information = rt_object_get_information(type);
    RT_ASSERT(information != RT_NULL);

    /* check object type to avoid re-initialization */

    /* enter critical */
    rt_enter_critical();
    /* try to find object */
    for (node  = information->object_list.next;
            node != &(information->object_list);
            node  = node->next)
    {
        struct rt_object *obj;

        obj = rt_list_entry(node, struct rt_object, list);
        if (obj) /* skip warning when disable debug */
        {
            RT_ASSERT(obj != object);
        }
    }
    /* leave critical */
    rt_exit_critical();

    /* initialize object's parameters */
    /* set object type to static */
    object->type = type | RT_Object_Class_Static;
    /* copy name */
    rt_strncpy(object->name, name, RT_NAME_MAX);

    RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));

    /* lock interrupt */
    temp = rt_hw_interrupt_disable();

#ifdef RT_USING_MODULE
    if (module)
    {
        rt_list_insert_after(&(module->object_list), &(object->list));
        object->module_id = (void *)module;
    }
    else
#endif /* RT_USING_MODULE */
    {
        /* insert object into information object list */
        rt_list_insert_after(&(information->object_list), &(object->list));
    }

    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
}

rt_object_detach

/**
 * @brief This function will detach a static object from object system,
 *        and the memory of static object is not freed.
 *
 * @param object the specified object to be detached.
 */
void rt_object_detach(rt_object_t object)
{
    register rt_base_t temp;

    /* object check */
    RT_ASSERT(object != RT_NULL);

    RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));

    /* reset object type */
    object->type = 0;

    /* lock interrupt */
    temp = rt_hw_interrupt_disable();

    /* remove from old list */
    rt_list_remove(&(object->list));

    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);
}

如果使用HEAP,#ifdef RT_USING_HEAP ,则有下面的函数rt_object_allocate和rt_object_delete

rt_object_allocate

/**
 * @brief This function will allocate an object from object system.
 *
 * @param type is the type of object.
 *
 * @param name is the object name. In system, the object's name must be unique.
 *
 * @return object
 */
rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name)
{
    struct rt_object *object;
    register rt_base_t temp;
    struct rt_object_information *information;
#ifdef RT_USING_MODULE
    struct rt_dlmodule *module = dlmodule_self();
#endif /* RT_USING_MODULE */

    RT_DEBUG_NOT_IN_INTERRUPT;

    /* get object information */
    information = rt_object_get_information(type);
    RT_ASSERT(information != RT_NULL);

    object = (struct rt_object *)RT_KERNEL_MALLOC(information->object_size);
    if (object == RT_NULL)
    {
        /* no memory can be allocated */
        return RT_NULL;
    }

    /* clean memory data of object */
    rt_memset(object, 0x0, information->object_size);

    /* initialize object's parameters */

    /* set object type */
    object->type = type;

    /* set object flag */
    object->flag = 0;

    /* copy name */
    rt_strncpy(object->name, name, RT_NAME_MAX);

    RT_OBJECT_HOOK_CALL(rt_object_attach_hook, (object));

    /* lock interrupt */
    temp = rt_hw_interrupt_disable();

#ifdef RT_USING_MODULE
    if (module)
    {
        rt_list_insert_after(&(module->object_list), &(object->list));
        object->module_id = (void *)module;
    }
    else
#endif /* RT_USING_MODULE */
    {
        /* insert object into information object list */
        rt_list_insert_after(&(information->object_list), &(object->list));
    }

    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);

    /* return object */
    return object;
}

rt_object_delete

/**
 * @brief This function will delete an object and release object memory.
 *
 * @param object is the specified object to be deleted.
 */
void rt_object_delete(rt_object_t object)
{
    register rt_base_t temp;

    /* object check */
    RT_ASSERT(object != RT_NULL);
    RT_ASSERT(!(object->type & RT_Object_Class_Static));

    RT_OBJECT_HOOK_CALL(rt_object_detach_hook, (object));

    /* reset object type */
    object->type = RT_Object_Class_Null;

    /* lock interrupt */
    temp = rt_hw_interrupt_disable();

    /* remove from old list */
    rt_list_remove(&(object->list));

    /* unlock interrupt */
    rt_hw_interrupt_enable(temp);

    /* free the memory of object */
    RT_KERNEL_FREE(object);
}

rt_object_is_systemobject

/**
 * @brief This function will judge the object is system object or not.
 *
 * @note  Normally, the system object is a static object and the type
 *        of object set to RT_Object_Class_Static.
 *
 * @param object is the specified object to be judged.
 *
 * @return RT_TRUE if a system object, RT_FALSE for others.
 */
rt_bool_t rt_object_is_systemobject(rt_object_t object)
{
    /* object check */
    RT_ASSERT(object != RT_NULL);

    if (object->type & RT_Object_Class_Static)
        return RT_TRUE;

    return RT_FALSE;
}

rt_object_get_type

/**
 * @brief This function will return the type of object without
 *        RT_Object_Class_Static flag.
 *
 * @param object is the specified object to be get type.
 *
 * @return the type of object.
 */
rt_uint8_t rt_object_get_type(rt_object_t object)
{
    /* object check */
    RT_ASSERT(object != RT_NULL);

    return object->type & ~RT_Object_Class_Static;
}

rt_object_find

/**
 * @brief This function will find specified name object from object
 *        container.
 *
 * @param name is the specified name of object.
 *
 * @param type is the type of object
 *
 * @return the found object or RT_NULL if there is no this object
 * in object container.
 *
 * @note this function shall not be invoked in interrupt status.
 */
rt_object_t rt_object_find(const char *name, rt_uint8_t type)
{
    struct rt_object *object = RT_NULL;
    struct rt_list_node *node = RT_NULL;
    struct rt_object_information *information = RT_NULL;

    information = rt_object_get_information((enum rt_object_class_type)type);

    /* parameter check */
    if ((name == RT_NULL) || (information == RT_NULL)) return RT_NULL;

    /* which is invoke in interrupt status */
    RT_DEBUG_NOT_IN_INTERRUPT;

    /* enter critical */
    rt_enter_critical();

    /* try to find object */
    rt_list_for_each(node, &(information->object_list))
    {
        object = rt_list_entry(node, struct rt_object, list);
        if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
        {
            /* leave critical */
            rt_exit_critical();

            return object;
        }
    }

    /* leave critical */
    rt_exit_critical();

    return RT_NULL;
}

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

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

相关文章

Java语言程序设计篇一

Java语言概述 Java语言起源编程语言最新排名名字起源Java语言发展历程Java语言的特点Java虚拟机垃圾回收Java语言规范Java技术简介Java程序的结构Java程序注意事项&#xff1a;注释编程风格练习 Java语言起源 1990年Sun公司提出一项绿色计划。1992年语言开发成功最初取名为Oak…

vue3使用方式汇总

1、引入iconfont阿里图库图标&#xff1a; 1.1 进入阿里图标网站&#xff1a; iconfont阿里&#xff1a;https://www.iconfont.cn/ 1.2 添加图标&#xff1a; 1.3 下载代码&#xff1a; 1.4 在vue3中配置代码&#xff1a; 将其代码复制到src/assets/fonts/目录下&#xff1…

大众点评2024年全球必吃榜清单

大众点评2024年全球必吃榜清单共2797家&#xff0c;奇怪的是官方并没有发布详细清单&#xff0c;只发布了新闻通稿介绍大概情况。这里做一些整理。 按城市分布情况&#xff0c;数量如下 上海 144 北京 137 成都 96 重庆 93 广州 81 深圳 79 武汉 69 苏州 67 杭州 61 …

应急响应--网站(web)入侵篡改指南

免责声明:本文... 目录 被入侵常见现象: 首要任务&#xff1a; 分析思路&#xff1a; 演示案例: IIS&.NET-注入-基于时间配合日志分析 Apache&PHP-漏洞-基于漏洞配合日志分析 Tomcat&JSP-弱口令-基于后门配合日志分析 (推荐) Webshell 查杀-常规后门&…

17_VGG深度学习图像分类算法

1.1 简介 VGG网络&#xff0c;全称为Visual Geometry Group网络&#xff0c;是由牛津大学的Visual Geometry Group和谷歌DeepMind的研究人员共同提出的深度卷积神经网络模型。这一模型因在2014年ILSVRC&#xff08;ImageNet大规模视觉识别挑战赛&#xff09;中取得图像分类任务…

昇思25天学习打卡营第4天|MindSpore数据集和数据变换

# 打卡 目录 # 打卡 Dateset&#xff1a;Pipeline 的起始 具体步骤 数据处理 Pipeline 代码例子 内置数据集的情况 自定义数据集的情况 可迭代的数据集 生成器 Transforms&#xff1a;数据预处理 代码例子 通用变换Compose 文本变换 Text Lambda变换 Dateset&…

STM32芯片系列与产品后缀解读

一. 产品系列 STM32单片机是一系列基于ARM Cortex-M内核的32位微控制器&#xff0c;广泛应用于嵌入式系统中。 STM32系列由STMicroelectronics&#xff08;意法半导体&#xff09;开发和生产&#xff0c;并凭借其灵活的设计、丰富的外设和强大的生态系统&#xff0c;成为嵌入式…

JVM专题之G1垃圾收集器下

索引(记录)的源码的工作流程图如下: CSet(Collection Set 回收集合) 收集集合(CSet)代表每次GC暂停时回收的一系列目标分区。在任意一次收集暂停中,CSet所有分区都会被释放,内部存活的对象都会被转移到分配的空闲分区中。因此无论是年轻代收集,还是混合收集,工作的机…

catia数控加工仿真铣平面粗加工

1&#xff0c;零件建模&#xff0c;毛坯建模 2 在毛坯上建立坐标系 3 添加资料刀具 4&#xff0c;双击对相关加工信息做设置 5 Roughing 加工设置 高亮红色区域是必选的&#xff0c;其他可以默认 6 完成加工仿真 7 加工余量

IntelliJ IDEA 同时多行同时编辑操作快捷键

首先 点击要编辑的地方,长按鼠标左键不放,同时按住 Ctrl Shift Alt,然后就可以进行多行编辑了

亲密数对C++函数

自定义函数 #include<bits/stdc.h> using namespace std; //求n的因子和自定义函数 int yinzihe(int n){//使用2~sqrt(n)成对求解因子和int r0,i;//变量 r 初始值为0&#xff0c;因为要存放因子和for(i2;i<sqrt(n);i) {//回顾sqrt()课程//如果 i 是 n 的因子&#xf…

用win的控制台去远程连接虚拟机linux的终端

以Ubuntu为例&#xff0c;首先确保Ubuntu已经安装了ssh服务 sudo apt-get install openssh-server输入密码 安装完毕后查看ssh状态是否开启 sudo systemctl status ssh 显示绿色激活状态&#xff0c;可以关闭或开启 对应start和stop winr打开win端控制台 输入 ssh -p 22 …

【Linux详解】进程等待 | 非阻塞轮询

引入&#xff1a; 为什么&#xff1f;是什么&#xff1f;怎么办 是什么&#xff1f; 进程等待是指父进程暂停自己的执行&#xff0c;直到某个特定的子进程结束或发生某些特定的事件。 为什么&#xff1f; 僵尸进程刀枪不入&#xff0c;不可被杀死&#xff0c;存在内存泄露…

Codeforces Round 918 (Div. 4)(A~F)

目录 A. Odd One Out B. Not Quite Latin Square C. Can I Square? D. Unnatural Language Processing E. Romantic Glasses F. Greetings A. Odd One Out Problem - A - Codeforces 输出一个不同于其他两个数的数&#xff0c;用异或操作可以轻松解决。 void solve{int…

ompl.app的demo_OpenDEPlanning例子

编译了下OMPL和OMPL.app, 其中有个example 是用刚体动力学库ODE搭建的小车运动场景&#xff0c;找出小车到目标的路径&#xff0c;牵引小车跑到目标位置。 ompl小车路径运动模拟

https 自签证书相关生成csr文件、p12文件、crt文件、jks文件、key文件、pem文件

文章目录 前言https 自签证书相关生成csr文件、p12文件、crt文件、jks文件、key文件、pem文件1, 检查openssl的版本2. 生成私钥和证书签署请求 (CSR)3. 生成自签名证书4. 将证书和私钥转换为 PKCS12 格式的密钥库5. 创建信任库 (Truststore)6. 将 PKCS12 文件转换为 JKS 文件7.…

详解Python递归解决汉诺塔问题

Python递归解决汉诺塔问题 递归解决汉诺塔问题是经典的计算机科学问题&#xff0c;它涉及到如何将一堆盘子从一个柱子上移动到另一个柱子上&#xff0c;每次只能移动一个盘子&#xff0c;并且大盘子不能放在小盘子上面。 例如我们需要将a柱盘子全部移动到b柱&#xff0c;接下来…

程序员熬夜看欧洲杯被“冻住”,呼吸困难……

2024欧洲杯接近尾声&#xff0c;更是激发球迷兴趣。由于时差关系&#xff0c;很多球迷熬夜看球&#xff0c;啤酒、宵夜成了标配。然而&#xff0c;在这份欢乐背后&#xff0c;也隐藏着健康风险。 日前&#xff0c;浙江杭州29岁的程序员单先生熬夜与朋友看完球赛后开车回家&…

室内定位可视化:精准导航与实时位置展示

通过图扑室内定位可视化技术&#xff0c;提供精准的导航服务和实时位置展示&#xff0c;帮助用户高效找到目标地点&#xff0c;提升空间管理和资源配置的效率与体验。

Spring学习05-[AOP学习-AOP原理和事务]

AOP原理和事务 AOPAOP底层原理比如下面的代码案例手动模拟AOP 动态代理详解JDK动态代理 AOP AOP底层原理 当实现了AOP,Spring会根据当前的bean创建动态代理(运行时生成一个代理类) 面试题&#xff1a;为什么执行方法的时候&#xff0c;会执行切面里的通知方法&#xff1f; 比…