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

内核对象基类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_MODULEvoid      *module_id;                               /**< id of application module */
#endifrt_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_SEMAPHORERT_Object_Info_Semaphore,                          /**< The object is a semaphore. */
#endif
#ifdef RT_USING_MUTEXRT_Object_Info_Mutex,                              /**< The object is a mutex. */
#endif
#ifdef RT_USING_EVENTRT_Object_Info_Event,                              /**< The object is a event. */
#endif
#ifdef RT_USING_MAILBOXRT_Object_Info_MailBox,                            /**< The object is a mail box. */
#endif
#ifdef RT_USING_MESSAGEQUEUERT_Object_Info_MessageQueue,                       /**< The object is a message queue. */
#endif
#ifdef RT_USING_MEMHEAPRT_Object_Info_MemHeap,                            /**< The object is a memory heap */
#endif
#ifdef RT_USING_MEMPOOLRT_Object_Info_MemPool,                            /**< The object is a memory pool. */
#endif
#ifdef RT_USING_DEVICERT_Object_Info_Device,                             /**< The object is a device */
#endifRT_Object_Info_Timer,                              /**< The object is a timer. */
#ifdef RT_USING_MODULERT_Object_Info_Module,                             /**< The object is a module. */
#endif
#ifdef RT_USING_HEAPRT_Object_Info_Memory,                            /**< The object is a memory. */
#endifRT_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_MODULEstruct 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_MODULEif (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_MODULEstruct 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_MODULEif (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.mzph.cn/web/41092.shtml

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

相关文章

清新简约之美,开源个人博客:Jekyll Theme Chirpy

Jekyll Theme Chirpy&#xff1a;简约不简单&#xff0c;Chirpy 让你的博客焕发新意- 精选真开源&#xff0c;释放新价值。 概览 Jekyll Theme Chirpy 是为Jekyll静态网站生成器设计的现代主题&#xff0c;以其清新、简约的设计风格和用户友好的交互体验受到开发者和博客作者的…

为企业知识库选模型?全球AI大模型知识库RAG场景基准测试排名

大语言模型常见基准测试 大家对于AI模型理解和推理能力的的基准测试一定非常熟悉了&#xff0c;比如MMLU&#xff08;大规模多任务语言理解&#xff09;、GPQA&#xff08;研究生级别知识问答&#xff09;、GSMSK&#xff08;研究生数学知识考察&#xff09;、MATH&#xff08…

Zabbix监控软件

目录 一、什么是Zabbix 二、zabbix监控原理 三、zabbix 安装步骤 一、什么是Zabbix ●zabbix 是一个基于 Web 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。 ●zabbix 能监视各种网络参数&#xff0c;保证服务器系统的安全运营&#xff1b;并提供灵活的…

python读取写入txt文本文件

读取 txt 文件 def read_txt_file(file_path):"""读取文本文件的内容:param file_path: 文本文件的路径:return: 文件内容"""try:with open(file_path, r, encodingutf-8) as file:content file.read()return contentexcept FileNotFoundError…

Swagger的原理及应用详解(十)

本系列文章简介&#xff1a; 在当今快速发展的软件开发领域&#xff0c;特别是随着微服务架构和前后端分离开发模式的普及&#xff0c;API&#xff08;Application Programming Interface&#xff0c;应用程序编程接口&#xff09;的设计与管理变得愈发重要。一个清晰、准确且易…

【多线程】进程与线程

&#x1f3c0;&#x1f3c0;&#x1f3c0;来都来了&#xff0c;不妨点个关注&#xff01; &#x1f3a7;&#x1f3a7;&#x1f3a7;博客主页&#xff1a;欢迎各位大佬! 文章目录 1. 操作系统1.1 什么是操作系统1.2 操作系统主要的功能 2. 进程2.1 什么是进程2.2 通过PCB描述一…

jEasyUI 创建菜单按钮

jEasyUI 创建菜单按钮 jEasyUI(jQuery EasyUI)是一个基于jQuery的用户界面插件集合,它为用户提供了一系列的UI组件,如菜单、按钮、表格等,以简化Web页面的开发过程。在本文中,我们将重点介绍如何使用jEasyUI创建菜单按钮。 1. 环境准备 在开始之前,请确保您的开发环境…

使用Python绘制甘特图

使用Python绘制甘特图 甘特图效果代码 甘特图 甘特图是一种项目管理工具&#xff0c;用于展示项目进度和任务安排。它通过条状图形表示各任务的起止时间&#xff0c;便于直观地查看项目的各个任务的进度和相互关系。 效果 [外链图片转存失败,源站可能有防盗链机制,建议将图片…

(void) (_x == _y)的作用

在阅读宋宝华的《Linux设备驱动开发详解》一书时&#xff0c;看到下面这段代码&#xff1a; #define min(x, y) ({ \ const typeof(x) _x (x); \ const typeof(y) -y (y); \ (void) (&_x &_y); \ _x < _y ? _x : _y; }) 这段代码可以理解如…

变量和标识符

一、变量 变量 数据类型 变量名初始值 常量的定义方式 1.#define 宏常量 (Day是常量&#xff0c;一旦修改就会报错) /2.const修饰的变量 #include <iostream> using namespace std; //变量 数据类型 变量名初始值 //常量的定义方式 //1.#define 宏常量 (Day是常量&…

Vue.js 基础入门指南

前言 在前端开发的广阔领域中&#xff0c;Vue.js 无疑是一颗璀璨的明星&#xff0c;以其渐进式框架的特性吸引了无数开发者的目光。Vue.js 旨在通过简洁的 API 实现响应式的数据绑定和组合的视图组件&#xff0c;使得构建用户界面变得既快速又简单。本文将带你走进 Vue.js 的世…

学习探索RASP:下一代应用安全防护技术

在当今数字化浪潮中&#xff0c;各类信息系统、应用程序不仅是企业数字化转型的驱动力&#xff0c;也成为了网络攻击的集中地带。面对日益复杂多变的网络安全威胁&#xff0c;防火墙等传统防护手段逐渐显得力不从心。在此背景下&#xff0c;寻求一种更为智能、高效且能深度融入…

代码随想录算法训练营第22天|LeetCode 77. 组合、216.组合总和III、17.电话号码的字母组合

1. LeetCode 77. 组合 题目链接&#xff1a;https://leetcode.cn/problems/combinations/description/ 文章链接&#xff1a;https://programmercarl.com/0077.组合.html 视频链接&#xff1a;https://www.bilibili.com/video/BV1ti4y1L7cv 思路&#xff1a;利用递归回溯的方式…

Codeforces Round 954 (Div. 3)

这里写自定义目录标题 A. X Axis题意&#xff1a;题解&#xff1a;代码&#xff1a; B. Matrix Stabilization题意&#xff1a;题解&#xff1a;代码&#xff1a; C. Update Queries题意&#xff1a;题解&#xff1a;代码&#xff1a; D. Mathematical Problem题意&#xff1a;…

nanodiffusion代码逐行理解之diffusion

目录 一、diffusion创建二、GaussianDiffusion定义三、代码理解def __init__(self,model,img_size,img_channels,num_classes,betas, loss_type"l2", ema_decay0.9999, ema_start5000, ema_update_rate1,):def remove_noise(self, x, t, y, use_emaTrue):def sample(…

MySQL 集群

MySQL 集群有多种类型&#xff0c;每种类型都有其特定的用途和优势。以下是一些常见的 MySQL 集群解决方案&#xff1a; 1. MySQL Replication 描述&#xff1a;MySQL 复制是一种异步复制机制&#xff0c;允许将一个 MySQL 数据库的数据复制到一个或多个从服务器。 用途&…

bug——多重定义

bug——多重定义 你的问题是在C代码中遇到了"reference to data is ambiguous"的错误。这个错误通常发生在你尝试引用一个具有多重定义的变量时。 在你的代码中&#xff0c;你定义了一个全局变量data&#xff0c;同时&#xff0c;C标准库中也有一个名为data的函数模板…

【云原生】Kubernetes部署高可用平台手册

部署Kubernetes高可用平台 文章目录 部署Kubernetes高可用平台基础环境一、基础环境配置1.1、关闭Swap1.2、添加hosts解析1.3、桥接IPv4流量传递到iptables的链 二、配置Kubernetes的VIP2.1、安装Nginx2.2、修改Nginx配置文件2.3、启动服务2.4、安装Keepalived2.5、修改配置文件…

Linux 定时任务详解:全面掌握 cron 和 at 命令

Linux 定时任务详解&#xff1a;全面掌握 cron 和 at 命令 Linux 系统中定时任务的管理对于运维和开发人员来说都是至关重要的。通过定时任务&#xff0c;可以在特定时间自动执行脚本或命令&#xff0c;提高系统自动化程度。本文将详细介绍 Linux 中常用的定时任务管理工具 cr…

一拖二快充线:生活充电新风尚,高效便捷解决双设备充电难题

一拖二快充线在生活应用领域的优势与双接充电的便携性问题 在现代快节奏的生活中&#xff0c;电子设备已成为我们不可或缺的日常伴侣。无论是智能手机、平板电脑还是笔记本电脑&#xff0c;它们在我们的工作、学习和娱乐中扮演着至关重要的角色。然而&#xff0c;随着设备数量…