FreeRTOS基础(九):FreeRTOS的列表和列表项

        今天我们将探讨FreeRTOS中的一个核心概念——列表(List)和列表项(List Item)。在实时操作系统(RTOS)中,任务的管理和调度是至关重要的,而FreeRTOS使用列表来实现这一功能。列表可以说是FreeRTOS中的一种数据结构,通过列表,我们可以高效地组织、排序和管理任务、定时器、事件等各种系统资源。具体来说,列表项是组成列表的基本单位,每个列表项都包含指向具体任务或事件的指针,以及用于排序的数值。希望通过今天的学习,大家能够掌握利用列表和列表项来实现任务调度的原理,并能够独立看懂源码。

目录

一、列表和列表项简介

1.1 列表和列表项的概念

1.2 列表结构体

1.3 列表项结构体

1.4 迷你列表项结构体

1.5 列表和列表项的关系

二、列表相关API函数介绍

2.1 初始化列表函数vListInitialise()

2.2 初始化列表项函数vListInitialiseItem()

2.3 列表项升序插入函数vListInsert()

2.3.1 源码分析

2.3.2 举例理解

2.4 列表项尾插函数vListInsertEnd()

2.4.1 源码分析

2.4.2 举例理解

2.5 列表项删除函数uxListRemove()

三、列表项的插入和删除实验

3.1  创建任务及实现任务函数

3.2 主函数调用入口函数,操作系统开始进行任务的切换和调度

3.3  实验结果


一、列表和列表项简介

1.1 列表和列表项的概念

       列表是 FreeRTOS 中的一个数据结构,概念上和链表有点类似,列表被用来跟踪 FreeRTOS中的任务。任务处在不同的状态下,就挂载在不同的列表中(比如就绪列表、阻塞列表、挂起列表)。 而列表项就是存放在列表中的项目,一个列表项就关联着一个任务,可以说:列表代表处于某种状态的任务的集合,列表项就代表处于当前状态下的某一个任务。如下图所示:

 

       列表相当于链表,列表项相当于节点,FreeRTOS 中的列表是一个双向循环链表,每个列表项有前驱结点指针prev,同时又有后继结点指针next,这样,双向循环链表的增删改查非常方便,动态改变,节省内存!列表的特点:列表项间的地址非连续的,是人为的连接到一起的。列表项的数目是由后期添加的个数决定的,随时可以改变,而数组的特点:数组成员地址是连续的,数组在最初确定了成员数量后期无法改变。

       在操作系统FreeRTOS中,任务的数量是不确定的,随时发生变化,并且任务状态是会发生改变的,所以非常适用列表(链表)这种数据结构。

1.2 列表结构体

 有关于列表的东西均在文件 list.c 和 list.h 中,首先我们先看下在list.h中的,列表相关结构体:

  1. 在该结构体中, 包含了两个宏(第一个和最后一个),这两个宏是确定的已知常量, FreeRTOS通过检查这两个常量的值,来判断列表的数据在程序运行过程中,是否遭到破坏 ,该功能一般用于调试, 默认是不开启的;
  2. 成员uxNumberOfItems,用于记录列表中列表项的个数(不包含末尾列表项,即最后一个列表项 xListEnd);
  3. 成员 pxIndex 用于指向列表中的某个列表项,一般用于遍历列表中的所有列表项(其实就是列表项指针);
  4. 成员变量 xListEnd 是一个迷你列表项,排在最末尾;

1.3 列表项结构体

       列表项是列表中用于存放数据的地方(每一个列表项关联着一个任务,在列表项里面有一个成员变量,用来存放任务控制块,描述这个任务的相关属性信息),在 list.h 文件中,有列表项的相关结构体定义:

1、成员变量 xItemValue 为列表项的值,这个值多用于按升序对列表中的列表项进行排序,插入列表项的时候可根据此值来确定插入的位置。比如通过延时阻塞的任务(对应一个列表项),它有一个延时时间,那么就根据延时时间在列表中进行排列,这样就可以实现优先解除时间短的任务。

2、成员变量 pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项 ,其实就是双向循环链表的前驱结点指针和后继结点指针;

3、成员变量 pxOwner 用于指向包含列表项的对象(通常是任务控制块,存储该任务的相关属性信息)

4、成员变量 pxContainer 用于指向列表项所在的列表(当前列表项在哪种列表中,就绪?阻塞?挂起?)。即指向归属的列表!

        通过成员3和成员4就可以确定该列表项属于哪个任务(任务控制块),并且在哪一种状态下。例如:第3个成员变量为任务1的控制块,第4个成员变量为就绪列表,那么就可以确定任务1处在就绪状态下!

1.4 迷你列表项结构体

          迷你列表项也是列表项,但迷你列表项仅用于标记列表的末尾挂载其他插入列表中的列表项,挂载如何理解:列表初始化的时候,只有一个迷你列表项,当插入新的列表项时,就把新的列表项对应的两只手(前驱指针和后继指针)牵上迷你列表项即可!迷你列表项没有存储数据,不会存储实际的任务数据信息,因此不需要成员变量 pxOwner 和 pxContainer,以节省内存开销!

1、成员变量 xItemValue 为列表项的值,这个值多用于按升序对列表中的列表项进行排序

2、成员变量 pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项

1.5 列表和列表项的关系

宏观上看如下图:

二、列表相关API函数介绍

         常见的列表的相关API函数如下,其实从数据结构上来讲:就是双向循环链表的初始化、增删操作。

2.1 初始化列表函数vListInitialise()

        初始化列表就是为列表的结构体成员赋初值,此时列表只有一个末尾列表项。

函数原型
void vListInitialise( List_t * const pxList );

形参

描述

pxList

待初始化列表

 

 一开始,列表为空,只有一个末尾列表项,因此:

  1. 用于记录列表中列表项的个数的变量uxNumberOfItems应为0;
  2. 成员 pxIndex 用于指向列表中的某个列表项,此时应该指向末尾列表项;
  3. 末尾列表项的成员变量 xItemValue 应该是最大的,因为要保证放在最后一个位置;
  4. 末尾列表项的前驱结点指针和后继结点指针都应该指向它自己(和双向循环链表初始化一样);

2.2 初始化列表项函数vListInitialiseItem()

函数原型
void vListInitialiseItem( ListItem_t * const pxItem );

形参

描述

pxItem

待初始化列表项

 

2.3 列表项升序插入函数vListInsert()

2.3.1 源码分析

函数原型
void vListInsert  (  List_t * const pxList ,   ListItem_t * const pxNewListItem  )

形参

描述

pxList

插入到哪个列表

pxNewListItem

待插入列表项

此函数用于将待插入列表的列表项按照列表项值升序进行排序,有序地插入到列表中!

 

可以看到:函数vListInsert() 跟双向循环链表的按位置插入结点思想相同。

2.3.2 举例理解

总结:函数vListInsert(),是将待插入列表的列表项按照列表项值升序进行排序,有序地插入到列表中

2.4 列表项尾插函数vListInsertEnd()

2.4.1 源码分析

函数原型
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem );

       形参

描述

       pxList

插入到哪个列表

pxNewListItem

待插入列表项

2.4.2 举例理解

总结:函数vListInsertEnd(),是将待插入的列表项插入到列表 pxIndex 指针指向的列表项前面;它是一种无序的插入方法!!

2.5 列表项删除函数uxListRemove()

函数原型
UBaseType_t  uxListRemove (   ListItem_t *  const    pxItemToRemove ) 

此函数用于将列表项从列表项所在列表中移除。

形参

描述

pxItemToRemove

待移除的列表项

返回值

描述

整数

待移除列表项移除后,所在列表剩余列表项的数量

三、列表项的插入和删除实验

      本实验本质上其实就是对双向链表进行增删操作,为了验证结果,打印列表项的地址和前驱结点地址以及后继结点地址进行验证即可。

3.1  创建任务及实现任务函数

#include "stm32f4xx.h"                  // Device header
#include "stdio.h"
#include "FreeRTOS.h"
#include "task.h"
#include "dynamic.h"
#include "mydelay.h"/**********************START_TASK任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/#define        START_TASK_STACK_SIZE  128   //定义堆栈大小为128字(1字等于4字节)
#define        START_TASK_PRIO         1    //定义任务优先级,0-31根据任务需求
TaskHandle_t   start_task_handler;    //定义任务句柄(结构体指针)
void start_task(void* args);/**********************TASK1任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define  TASK1_STACK_SIZE  128            //定义堆栈大小为128字(1字等于4字节)
#define  TASK1_PRIO         2             //定义任务优先级,0-31根据任务需求
TaskHandle_t   task1_handler;           //定义任务句柄(结构体指针)
void task1(void* args);/**********************TASK2任务配置******************************/
/***********包括任务堆栈大小、任务优先级、任务句柄、创建任务***********/
#define  TASK2_STACK_SIZE  128            //定义堆栈大小为128字(1字等于4字节)
#define  TASK2_PRIO         3             //定义任务优先级,0-31根据任务需求
TaskHandle_t   task2_handler;           //定义任务句柄(结构体指针)
void task2(void* args);/*********开始任务用来创建一个任务,只创建一次,不能是死循环,创建完这个任务后删除开始任务本身***********/
void start_task(void* args)
{taskENTER_CRITICAL();        /*进入临界区*/xTaskCreate( (TaskFunction_t)         task1,(char *)     "task1",  ( configSTACK_DEPTH_TYPE)   TASK1_STACK_SIZE,(void *)      NULL,(UBaseType_t) TASK1_PRIO ,(TaskHandle_t *)  &task1_handler );xTaskCreate( (TaskFunction_t)         task2,(char *)     "task2",  ( configSTACK_DEPTH_TYPE)   TASK2_STACK_SIZE,(void *)      NULL,(UBaseType_t) TASK2_PRIO ,(TaskHandle_t *)  &task2_handler );							vTaskDelete(NULL);    //删除开始任务自身,传参NULLtaskEXIT_CRITICAL();   /*退出临界区*///临界区内不会进行任务的调度切换,出了临界区才会进行任务调度,抢占式						
}/********任务1的任务函数,无返回值且是死循环***********//***任务1:实现LED0每500ms翻转一次*******/
void task1(void* args)
{while(1){printf("22222\n");GPIO_ToggleBits(GPIOF,GPIO_Pin_9 );vTaskDelay(500);       //FreeRTOS自带的延时函数,延时500毫秒}	
}List_t       TestList;      /*定义测试列表*/
ListItem_t   ListItem1;    /*定义测试列表项1*/
ListItem_t   ListItem2;   /*定义测试列表项2*/
ListItem_t   ListItem3;   /*定义测试列表项3*//********任务2的任务函数,无返回值且是死循环***********//***任务2:列表项插入和删除实验*******/
void task2(void* args)
{vListInitialise( &TestList );         /*初始化列表*/vListInitialiseItem( &ListItem1);     /*初始化列表项1*/vListInitialiseItem( &ListItem2);     /*初始化列表项2*/vListInitialiseItem( &ListItem3);     /*初始化列表项3*/ListItem1.xItemValue=40;ListItem2.xItemValue=60;ListItem3.xItemValue=50;/*第二步:打印列表和其他列表项的地址*/printf("/************第二步:打印列表和列表项的地址************/\r\n");printf("项目\t\t\t地址\r\n" );printf("TestList\t\t0x%p\t\r\n",&TestList);                       //列表地址printf("TestList->pxIndex\t0x%p\t\r\n",TestList.pxIndex);        //列表中的列表项指针指向的列表项的地址printf("TestList- >xListEnd\t0x%p\t\r\n",(&TestList.xListEnd)); //末尾列表项的地址printf("ListIteml\t\t0x%p\t\r\n",&ListItem1);                   //列表项1的地址printf("ListItem2\t\t0x%p\t\r\n",&ListItem2);                   //列表项2的地址printf("ListItem3\t\t0x%p\t\r\n",&ListItem3);                   //列表项3的地址printf ("/***********************结束**********************/\r\n"); /*第三步:列表项1插入列表: */printf("\r\n***************第三步:列表项1插入列表***************/\r\n");vListInsert((List_t* )&TestList,                                 /* 列表  */(ListItem_t*) &ListItem1);                            /* 列表项 */printf("项目\t\t\t\t地址:\r\n");printf("TestList->xListEnd->pxNext\tOx%p\r\n ",(TestList.xListEnd.pxNext));printf("ListIteml->pxNext\t\t0x%p\r\n",(ListItem1.pxNext));printf("TestList->xListEnd->pxPrevious\t0x%p\r\n",(TestList.xListEnd.pxPrevious));printf("ListIteml->pxPrevious\t\t0x%p\r\n",(ListItem1.pxPrevious));printf ("/*************************结束**************************/\r\n");/*第四步:列表项2插入列表: */printf ("\r\n/************第四步:列表项2插入列表**************/\r\n");vListInsert((List_t* )&TestList,                                  /*  列表  */(ListItem_t*)&ListItem2);                              /*  列表项  */printf("项目\t\t\t\t地址\r\n" );printf("TestList->xListEnd->pxNext\t0x%p\r\n",(TestList.xListEnd.pxNext));printf("ListIteml->pxNext\t\t0x%p\r\n",(ListItem1.pxNext));printf("ListItem2->pxNext\t\t0x%p\r\n",(ListItem2.pxNext));printf("TestList->xListEnd->pxPrevious\t0x%p\r\n",(TestList.xListEnd.pxPrevious));printf("ListIteml->pxPrevious\t\t0x%p\r\n",(ListItem1. pxPrevious));printf("ListItem2->pxPrevious\t\t0x%p\r\n",(ListItem2. pxPrevious));printf ("/**************************结束***************************/\r\n");/* 第五步:列表项3插入列表 */printf("\r\n***************第五步:列表项3插入列表***************/\r\n");vListInsert((List_t* ) &TestList,                                /*  列表  */(ListItem_t*)&ListItem3);                            /*  列表项  */printf("项目\t\t\t\t地址\r\n");printf("TestList->xListEnd->px.Next\t0x%p\r\n",(TestList.xListEnd.pxNext));printf("ListIteml->pxNext\t\t0x%p\r\n",(ListItem1.pxNext));printf("ListItem2->pxNext\t\t0x%p\r\n",(ListItem2.pxNext));printf("ListItem3->pxNext\t\t0x%p\r\n",(ListItem3.pxNext));printf("TestList->xListEnd->pxPrevious\t0x%p\r\n",(TestList.xListEnd.pxPrevious));printf("ListIteml->pxPrevious\t\t0x%p\r\n",(ListItem1.pxPrevious));printf("ListItem2->pxPrevious\t\t0x%p\r\n",(ListItem2.pxPrevious));printf("ListItem3->pxPrevious\t\t0x%p\r\n",(ListItem3.pxPrevious));printf("/**************************结束***************************/\r\n");/*  第六步:移除列表项2 */printf("\r\n ****************第六步:移除列表项2******************/\r\n");uxListRemove((ListItem_t* )&ListItem2);                         /*   移除列表项   */printf("项月\t\t\t\t地址\r\n");printf("TestList->xListEnd->pxNext\t0x%p\r\n",(TestList.xListEnd.pxNext));printf("ListIteml->px.Next\t\t0x%p\r\n",(ListItem1.pxNext));printf("ListItem3->pxNext\t\t0x%p\r\n",(ListItem3.pxNext));printf("TestList->xListEnd->pxPrevious\t0x%p\r\n",(TestList.xListEnd.pxPrevious));printf("ListIteml->pxPrevious\t\t0x%p\r\n",(ListItem1.pxPrevious));printf("ListItem3->pxPrevious\t\t0x%p\r\n",(ListItem3.pxPrevious));printf("/**************************结束***************************/\r\n");/* 第七步:列表末尾添加列表项2 */printf("\r\n/ *************第七步:列表末尾添加列表项2**************/\r\n");vListInsertEnd((List_t*)&TestList,                              /*   列表     */(ListItem_t* )&ListItem2);                       /*   列表项   */printf("项目\t\t\t\t地址\r\n");printf("TestList->pxIndex\t\t0x%p\r\n",TestList.pxIndex);printf("TestList->xListEnd->pxNext\t0x%p\r\n",(TestList.xListEnd.pxNext));printf("ListIteml->pxNext\t\t0x%p\r\n",(ListItem1.pxNext));printf("ListItem2->pxNext\t\t0x%p\r\n",(ListItem2.pxNext));printf("ListItem3->pxNext\t\t0x%p\r\n",(ListItem3.pxNext));printf("TestList->xListEnd->pxPrevious\t0x%p\r\n",(TestList.xListEnd.pxPrevious));printf("ListIteml->pxPrevious\t\t0x%p\r\n",(ListItem1.pxPrevious));printf("ListItem2->pxPrevious\t\t0x%p\r\n",(ListItem2.pxPrevious));printf("ListItem3->pxPrevious\t\t0x%p\r\n",(ListItem3.pxPrevious));printf("/*********************实验结束***********************/\r\n");while(1){printf("11111\n");		vTaskDelay(1000);       //FreeRTOS自带的延时函数,延时1秒}	
}//FreeRTO入口例程函数,无参数,无返回值
void freertos_demo(void)
{xTaskCreate( (TaskFunction_t)     start_task,(char *)     "start_task",  ( configSTACK_DEPTH_TYPE)   START_TASK_STACK_SIZE,(void *)      NULL,(UBaseType_t) START_TASK_PRIO ,(TaskHandle_t *)  &start_task_handler );vTaskStartScheduler();  //开启任务调度器}

3.2 主函数调用入口函数,操作系统开始进行任务的切换和调度

#include "stm32f4xx.h"                  // Device header
#include "stdio.h"
#include "myled.h"
#include "myusart.h"#include "FreeRTOS.h"
#include "task.h"
#include "dynamic.h"extern TaskHandle_t Start_Handle;int main(void)
{//硬件初始化My_UsartInit();//调用入口函数freertos_demo();}

3.3  实验结果

根据每一步操作的地址,符合理论!

至此,已经讲解完毕!初次学习,循序渐进,一步步掌握即可!以上就是全部内容!请务必掌握,创作不易,欢迎大家点赞加关注评论,您的支持是我前进最大的动力!下期再见!

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

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

相关文章

oracle数据回显时候递归实战

太简单的两篇递归循环 orcale 在项目里递归循环实战 先看资产表T_ATOM_ASSET结构 看业务类别表T_ATOM_BUSI_CATEGORY结构 问题出现 页面显示 实际对应的归属业务分类 涉及到oracle递归实战(这里不会如何直接在atomAsset的seelct里面处理递归回显) 直接在实现层看atomAs…

NVIDIA - QPU

转载自 What Is a QPU? ( 2022 年 7 月 29 日 里克梅里特 https://blogs.nvidia.com/blog/what-is-a-qpu/ 文章目录 一、概述二、那么,什么是 QPU?三、量子处理器如何工作?四、制作量子比特的多种方法五、光的量子比特六、简单的芯片&#x…

李廉洋:6.2黄金原油持续走低,下周一行情走势分析及策略。

黄金消息面分析:尽管通胀数据显示出稳定迹象,但美联储对此仍持谨慎态度。美国商务部经济分析局发布的数据显示,4月PCE物价指数月率维持在0.3%,而消费者支出的增长放缓至0.2%,低于3月份的0.7%。这表明,尽管通…

CSAPP Lab07——Malloc Lab完成思路

等不到天黑 烟火不会太完美 回忆烧成灰 还是等不到结尾 ——她说 完整代码见:CSAPP/malloclab-handout at main SnowLegend-star/CSAPP (github.com) Malloc Lab 按照惯例,我先是上来就把mm.c编译了一番,结果产生如下报错。搜索过后看样子应…

SpringBoot:手动创建应用

Spring提供了在线的Spring Initialzr在线创建Spring Boot项目,为了更好的理解Spring Boot项目,这里我们选择手动创建。 1.新建Web应用 1.1 生成工程 首先要做是创建一个Java项目,这里我们选择使用Maven来支持,使用archetype:ge…

React + SpringBoot开发用户中心管理系统

用户中心项目搭建笔记 技术栈 前端技术栈 “react”: “^18.2.0”,ant-design-pro 后端技术栈 SpringBoot 2.6.x 项目源码地址 https://gitee.com/szxio/user-center 前端项目搭建 快速搭建一个后端管理系统项目框架 初始化 antDesignPro 官网: https://…

众汇:外汇狙击指标如何使用?

对于投资者来说,我们各位交易的目的是什么?WeTrade众汇认为那就是盈利。所以来说有一个指标对各位投资者来说那是相当有帮助的。这是因为对于交易者而言,利用这些指标可以快速识别盈利的买卖时机。当我们选择一个指标之后,深入了解其适用范围…

luckysheet的使用

前言 公司新需求要一个在线的excel编辑器 一、luckysheet是什么? LuckySheet是一款基于Web的在线表格组件,一款纯前端类似excel的在线表格,功能强大、配置简单、完全开源结合Vue3可以实现数据的动态展示和编辑,为用户提供良好的…

2024年四川省三支一扶报名流程图解✅

2024年四川省三支一扶报名流程图解✅ 🔴时间安排 1、报名时间:5月31日—6月4日17:00 2、资格初审时间:5月31日—6月5日17:00 3、准考证打印时间:6月25日—6月29日 4、笔试时间:6月30日 5、笔试成绩:7…

C++:特殊类设计和四种类型转换

一、特殊类设计 1.1 不能被拷贝的类 拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。 C98: 1、将拷贝构造函数与赋值运算符重载只…

【Unity Shader入门精要 第12章】屏幕后处理效果(三)

1. Bloom效果 Bloom描述的是图像中较亮的部分向周围一定范围内发生扩散,造成一种朦胧的效果,常用于表现游戏中的灯光或隧道出口之类的效果。 下面的例子将实现一个简单的Bloom效果,其原理是: 将原始图像中较亮(灰度…

2023-2025年最值得选择的Java毕业设计选题大全:1000个热门选题推荐✅✅✅

💗博主介绍:✌全网粉丝1W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,还…

密码加密及验证

目录 为什么需要加密? 密码算法分类 对称密码算法 非对称密码算法 摘要算法 DigestUtils MD5在线解密工具原理 实现用户密码加密 代码实现 为什么需要加密? 在MySQL数据库中,我们常常需要对用户密码、身份证号、手机号码等敏感信息进…

centos8stream 编译安装 php-rabbit-mq模块

官方GitHub:https://github.com/php-amqp/php-amqp 环境依赖安装 dnf install cmake make -y 1.安装rabbitmq-c cd /usr/local/src/ wget https://github.com/alanxz/rabbitmq-c/archive/refs/tags/v0.14.0.tar.gz tar xvf v0.14.0.tar.gz cd rabbitmq-c-0.14.0/…

NoSQL是什么?NoSQL数据库存在SQL注入攻击?

一、NoSQL是什么? NoSQL(Not Only SQL)是一种非关系型数据库的概念。与传统的关系型数据库不同,NoSQL数据库使用不同的数据模型来存储和检索数据。NOSQL数据库通常更适合处理大规模的非结构化和半结构化数据,且能够…

Docker-----emqx部署

emqx通过Docker容器化部署流程 1.创建持久化挂载目录 mkdir -p /home/emqx/etc ------挂载emqx的配置文件目录 mkdir -p /home/emqx/data ------挂载emqx的存储目录 mkdir -p /home/emqx/log ------挂载emqx的日志目录 [root home]# mkdir -p /home/emqx/etc [root home]# mkd…

IC芯片晶片固定保护环氧胶有什么优点?

IC芯片晶片固定保护环氧胶有什么优点? IC芯片晶片固定环氧胶在电子设备制造和组装中被广泛使用,主要用于电子封装和芯片固定应用,具有多种显著优点,其主要优点包括但不限于以下几点: 高强度粘接:环氧胶的固…

开源VS闭源:大模型发展路径之争,你站哪一派?

文章目录 引言一、数据隐私1.1开源大模型的数据隐私1.2 闭源大模型的数据隐私1.3 综合考量 二、商业应用2.1 开源大模型的商业应用2.2 闭源大模型的商业应用2.3 商业应用的综合考量 三、社区参与3.1 开源大模型的社区参与3.2 闭源大模型的社区参与3.3 综合考量 结论 引言 在人…

1.JAVA小项目(零钱通)

一、说明 博客内容:B站韩顺平老师的视频,以及代码的整理。此项目分为两个版本: 面向过程思路实现面向对象思路实现 韩老师视频地址:【【零基础 快速学Java】韩顺平 零基础30天学会Java】 https://www.bilibili.com/video/BV1fh4…

Django基础学习(一)

前端开发 目的:开发一个平台(网站)- 前端开发: HTML, CSS,JavaScript- web框架:接收请求并进行处理- MySQL数据库:存储相应的数据1.快速开发网站 pip install flask创建项目并导入flask框架,然后建立网址和函数的对应关系。 fr…