(学习日记)2024.04.06:UCOSIII第三十四节:互斥量函数接口讲解

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2024.04.06

  • 四十八、UCOSIII:互斥量函数接口讲解
    • 1、创建互斥量函数OSMutexCreate()
    • 2、删除互斥量函数OSMutexDel()
    • 3、获取互斥量函数OSMutexPend()
    • 4、释放互斥量函数OSMutexPost()

四十八、UCOSIII:互斥量函数接口讲解

1、创建互斥量函数OSMutexCreate()

在定义完互斥量结构体变量后就可以调用 OSMutexCreate()函数进行创建一个互斥量,跟信号量的创建差不多。
这里的“创建互斥量”指的就是对内核对象(互斥量)的一些初始化。
要特别注意的是内核对象使用之前一定要先创建, 这个创建过程必须要保证在所有可能使用内核对象的任务之前,所以一般我们都是在创建任务之前就创建好系统需要的内核对象(如互斥量等)。
创建互斥量函数OSMutexCreate()源码具体如下:

void  OSMutexCreate (OS_MUTEX  *p_mutex, (1)        //互斥量指针CPU_CHAR  *p_name,  (2) //取互斥量的名称OS_ERR    *p_err)   (3) //返回错误类型
{CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必须用到该宏,该宏声明和//定义一个局部变量,用于保存关中断前的 CPU 状态寄存器// SR(临界段关中断只需保存SR),开中断时将该值还原。#ifdef OS_SAFETY_CRITICAL(4)//如果启用(默认禁用)了安全检测if (p_err == (OS_ERR *)0)           //如果错误类型实参为空{OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数return;                         //返回,不继续执行}
#endif#ifdef OS_SAFETY_CRITICAL_IEC61508(5)//如果启用(默认禁用)了安全关键//如果是在调用 OSSafetyCriticalStart()后创建if (OSSafetyCriticalStartFlag == DEF_TRUE){*p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; //错误类型为“非法创建内核对象”return;                                  //返回,不继续执行}
#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u       (6)//如果启用(默认启用)了中断中非法调用检测if (OSIntNestingCtr > (OS_NESTING_CTR)0)     //如果该函数是在中断中被调用{*p_err = OS_ERR_CREATE_ISR;             //错误类型为“在中断函数中定时”return;                                  //返回,不继续执行}
#endif#if OS_CFG_ARG_CHK_EN > 0u(7)//如果启用(默认启用)了参数检测if (p_mutex == (OS_MUTEX *)0) //如果参数 p_mutex 为空{*p_err = OS_ERR_OBJ_PTR_NULL;  //错误类型为“创建对象为空”return;                       //返回,不继续执行}
#endifOS_CRITICAL_ENTER();              //进入临界段,初始化互斥量指标//标记创建对象数据结构为互斥量p_mutex->Type              =  OS_OBJ_TYPE_MUTEX;  (8)p_mutex->NamePtr           =  p_name;           (9)p_mutex->OwnerTCBPtr       = (OS_TCB       *)0; (10)p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)0; (11)p_mutex->TS                = (CPU_TS        )0; (12)p_mutex->OwnerOriginalPrio =  OS_CFG_PRIO_MAX;OS_PendListInit(&p_mutex->PendList);        //初始化该互斥量的等待列表#if OS_CFG_DBG_EN > 0u//如果启用(默认启用)了调试代码和变量OS_MutexDbgListAdd(p_mutex); //将该互斥量添加到互斥量双向调试链表
#endifOSMutexQty++;                   (13)//互斥量个数加1OS_CRITICAL_EXIT_NO_SCHED();    (14)    //退出临界段(无调度)*p_err = OS_ERR_NONE;                   //错误类型为“无错误”
}
  • (1):互斥量控制块指针, 指向我们定义的互斥量控制块结构体变量,所以在创建之前我们需要先定义一个互斥量控制块变量。
  • (2):互斥量名称,字符串形式。
  • (3):用于保存返回的错误类型。
  • (4):如果启用了安全检测(默认禁用), 在编译时则会包含安全检测相关的代码,如果错误类型实参为空,系统会执行安全检测异常函数,然后返回,不执行创建互斥量操作。
  • (5):如果启用(默认禁用)了安全关键检测, 在编译时则会包含安全关键检测相关的代码,如果是在调用OSSafetyCriticalStart()后创建该互斥量,则是非法的, 返回错误类型为“非法创建内核对象”错误代码,并且退出,不执行创建互斥量操作。
  • (6):如果启用了中断中非法调用检测(默认启用), 在编译时则会包含中断非法调用检测相关的代码,如果该函数是在中断中被调用,则是非法的,返回错误类型为“在中断中创建对象”的错误代码, 并且退出,不执行创建互斥量操作。
  • (7):如果启用了参数检测(默认启用), 在编译时则会包含参数检测相关的代码,如果p_mutex参数为空,返回错误类型为“创建对象为空”的错误代码,并且退出,不执行创建互斥量操作。
  • (8):标记创建对象数据结构为互斥量。
  • (9):初始化互斥量的名称。
  • (10):初始化互斥量结构体中的OwnerTCBPtr成员变量,目前系统中尚无任务持有互斥量。
  • (11):初始化互斥量结构体中的OwnerNestingCtr成员变量为0,表示互斥量可用。
  • (12):记录时间戳的变量TS初始化为0。 初始化互斥量结构体中的OwnerOriginalPrio成员变量为OS_CFG_PRIO_MAX(最低优先级)。初始化该互斥量的等待列表等。
  • (13):系统中互斥量个数加1。
  • (14):退出临界段(无调度),创建互斥量成功。

如果我们创建一个互斥量,那么互斥量创建成功的示意图具体见图
在这里插入图片描述

互斥量创建函数的使用实例具体如下:

OS_MUTEX mutex;                         //声明互斥量
/* 创建互斥量 mutex */
OSMutexCreate ((OS_MUTEX  *)&mutex,           //指向互斥量变量的指针(CPU_CHAR  *)"Mutex For Test", //互斥量的名字(OS_ERR    *)&err);            //错误类型

2、删除互斥量函数OSMutexDel()

OSSemDel()用于删除一个互斥量,互斥量删除函数是根据互斥量结构(互斥量句柄)直接删除的,删除之后这个互斥量的所有信息都会被系统清空, 而且不能再次使用这个互斥量了。
需要注意的是,如果某个互斥量没有被定义,那也是无法被删除的,如果有任务阻塞在该互斥量上, 那么尽量不要删除该互斥量。想要使用互斥量删除函数就必须将OS_CFG_MUTEX_DEL_EN宏定义配置为1,其函数源码具体如下

#if OS_CFG_MUTEX_DEL_EN > 0u        //如果启用了 OSMutexDel()
OS_OBJ_QTY  OSMutexDel (OS_MUTEX  *p_mutex, (1)     //互斥量指针OS_OPT     opt,     (2)     //选项OS_ERR    *p_err)   (3)     //返回错误类型
{OS_OBJ_QTY     cnt;OS_OBJ_QTY     nbr_tasks;OS_PEND_DATA  *p_pend_data;OS_PEND_LIST  *p_pend_list;OS_TCB        *p_tcb;OS_TCB        *p_tcb_owner;CPU_TS         ts;CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必须用到该宏,该宏声明和//定义一个局部变量,用于保存关中断前的 CPU 状态寄存器// SR(临界段关中断只需保存SR),开中断时将该值还原。#ifdef OS_SAFETY_CRITICAL(4)//如果启用(默认禁用)了安全检测if (p_err == (OS_ERR *)0)           //如果错误类型实参为空{OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数return ((OS_OBJ_QTY)0);         //返回0(有错误),停止执行}
#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u(5)//如果启用了中断中非法调用检测if (OSIntNestingCtr > (OS_NESTING_CTR)0)  //如果该函数在中断中被调用{*p_err = OS_ERR_DEL_ISR;               //错误类型为“在中断中中止等待”return ((OS_OBJ_QTY)0);               //返回0(有错误),停止执行}
#endif#if OS_CFG_ARG_CHK_EN > 0u(6)//如果启用了参数检测if (p_mutex == (OS_MUTEX *)0)         //如果 p_mutex 为空{*p_err = OS_ERR_OBJ_PTR_NULL;      //错误类型为“对象为空”return ((OS_OBJ_QTY)0);           //返回0(有错误),停止执行}switch (opt)                   (7)//根据选项分类处理{case OS_OPT_DEL_NO_PEND:          //如果选项在预期内case OS_OPT_DEL_ALWAYS:break;                       //直接跳出default:                     (8)//如果选项超出预期*p_err =  OS_ERR_OPT_INVALID; //错误类型为“选项非法”return ((OS_OBJ_QTY)0);      //返回0(有错误),停止执行}
#endif#if OS_CFG_OBJ_TYPE_CHK_EN > 0u(9)//如果启用了对象类型检测if (p_mutex->Type != OS_OBJ_TYPE_MUTEX)   //如果 p_mutex 非互斥量类型{*p_err = OS_ERR_OBJ_TYPE;              //错误类型为“对象类型错误”return ((OS_OBJ_QTY)0);               //返回0(有错误),停止执行}
#endifOS_CRITICAL_ENTER();                        //进入临界段p_pend_list = &p_mutex->PendList;     (10)//获取互斥量的等待列表cnt         = p_pend_list->NbrEntries;  (11)//获取等待该互斥量的任务数nbr_tasks   = cnt;switch (opt)                     (12)//根据选项分类处理{case OS_OPT_DEL_NO_PEND:         (13)//如果只在没任务等待时删除互斥量if (nbr_tasks == (OS_OBJ_QTY)0)    //如果没有任务在等待该互斥量{
#if OS_CFG_DBG_EN > 0u//如果启用了调试代码和变量OS_MutexDbgListRemove(p_mutex);//将该互斥量从互斥量调试列表移除
#endifOSMutexQty--;            (14)//互斥量数目减1OS_MutexClr(p_mutex);    (15)//清除互斥量内容OS_CRITICAL_EXIT();            //退出临界段*p_err = OS_ERR_NONE;    (16)//错误类型为“无错误”}else(17)//如果有任务在等待该互斥量{OS_CRITICAL_EXIT();             //退出临界段*p_err = OS_ERR_TASK_WAITING;  //错误类型为“有任务正在等待”}break;                             //跳出case OS_OPT_DEL_ALWAYS:            (18)//如果必须删除互斥量p_tcb_owner = p_mutex->OwnerTCBPtr;     (19)//获取互斥量持有任务if ((p_tcb_owner       != (OS_TCB *)0) &&//如果持有任务存在,(p_tcb_owner->Prio !=  p_mutex->OwnerOriginalPrio))//而且优先级被提升过。                (20){switch (p_tcb_owner->TaskState)     (21)//根据其任务状态处理{case OS_TASK_STATE_RDY:          (22)//如果是就绪状态OS_RdyListRemove(p_tcb_owner);       //将任务从就绪列表移除p_tcb_owner->Prio = p_mutex->OwnerOriginalPrio;(23)//还原任务的优先级OS_PrioInsert(p_tcb_owner->Prio);   (24)//将该优先级插入优先级表格OS_RdyListInsertTail(p_tcb_owner); (25)//将任务重插入就绪列表break;                                         //跳出case OS_TASK_STATE_DLY:              (26)//如果是延时状态case OS_TASK_STATE_SUSPENDED:          //如果是被挂起状态case OS_TASK_STATE_DLY_SUSPENDED:       //如果是延时中被挂起状态p_tcb_owner->Prio = p_mutex->OwnerOriginalPrio;//还原任务的优先级break;case OS_TASK_STATE_PEND:      (27)//如果是无期限等待状态case OS_TASK_STATE_PEND_TIMEOUT:         //如果是有期限等待状态case OS_TASK_STATE_PEND_SUSPENDED://如果是无期等待中被挂状态case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED://如果是有期等待中被挂状态OS_PendListChangePrio(p_tcb_owner,//改变任务在等待列表的位置p_mutex->OwnerOriginalPrio);break;default:                       (28)//如果状态超出预期OS_CRITICAL_EXIT();*p_err = OS_ERR_STATE_INVALID;//错误类型为“任务状态非法”return ((OS_OBJ_QTY)0);//返回0(有错误),停止执行}}ts = OS_TS_GET();                    (29)//获取时间戳while(cnt > 0u)                     (30)//移除该互斥量等待列表中的所有任务。{p_pend_data = p_pend_list->HeadPtr;p_tcb       = p_pend_data->TCBPtr;OS_PendObjDel((OS_PEND_OBJ *)((void *)p_mutex),p_tcb,ts);                (31)cnt--;}
#if OS_CFG_DBG_EN > 0u//如果启用了调试代码和变量OS_MutexDbgListRemove(p_mutex);    //将互斥量从互斥量调试列表移除
#endifOSMutexQty--;                (32)//互斥量数目减1OS_MutexClr(p_mutex);         (33)//清除互斥量内容OS_CRITICAL_EXIT_NO_SCHED();  (34)//退出临界段,但不调度OSSched();                    (35)//调度最高优先级任务运行*p_err = OS_ERR_NONE;(36)//错误类型为“无错误”
break;                             //跳出default:                         (37)//如果选项超出预期OS_CRITICAL_EXIT();                //退出临界段*p_err = OS_ERR_OPT_INVALID;        //错误类型为“选项非法”
break;                             //跳出}return (nbr_tasks);               (38)//返回删除前互斥量等待列表中的任务数
}
#endif
  • (1):互斥量控制块指针,指向我们定义的互斥量控制块结构体变量, 所以在删除之前我们需要先定义一个互斥量控制块变量,并且成功创建互斥量后再进行删除操作。
  • (2):互斥量删除的选项。
  • (3):用于保存返回的错误类型。
  • (4):如果启用了安全检测(默认), 在编译时则会包含安全检测相关的代码,如果错误类型实参为空,系统会执行安全检测异常函数,然后返回,不执行删除互斥量操作。
  • (5):如果启用了中断中非法调用检测(默认启用), 在编译时则会包含中断非法调用检测相关的代码,如果该函数是在中断中被调用,则是非法的,返回错误类型为“在中断中删除对象”的错误代码,并且退出,不执行删除互斥量操作。
  • (6):如果启用了参数检测(默认启用), 在编译时则会包含参数检测相关的代码,如果p_mutex参数为空,返回错误类型为“内核对象为空”的错误代码,并且退出,不执行删除互斥量操作。
  • (7):判断opt选项是否合理,该选项有两个, OS_OPT_DEL_ALWAYS与OS_OPT_DEL_NO_PEND,在os.h文件中定义。此处是判断一下选项是否在预期之内,如果在则跳出switch语句。
  • (8):如果选项超出预期,则返回错误类型为“选项非法”的错误代码,退出,不继续执行。
  • (9):如果启用了对象类型检测,在编译时则会包含对象类型检测相关的代码, 如果p_mutex不是互斥量类型,返回错误类型为“内核对象类型错误”的错误代码,并且退出,不执行删除互斥量操作。
  • (10):程序执行到这里,表示可以删除互斥量了,系统首先获取互斥量的等待列表保存到p_pend_list变量中。
  • (11):然后再获取等待该互斥量的任务数。
  • (12):根据选项分类处理。
  • (13):如果opt是OS_OPT_DEL_NO_PEND, 则表示只在没有任务等待的情况下删除互斥量,如果当前系统中有任务阻塞在该互斥量上,则不能删除,反之,则可以删除互斥量。
  • (14):如果没有任务在等待该互斥量,互斥量数目减1。
  • (15):清除互斥量内容
  • (16):删除成功,返回错误类型为“无错误”的错误代码。
  • (17):如果有任务在等待该互斥量,则返回错误类型为“有任务在等待该互斥量”错误代码。
  • (18):如果opt是OS_OPT_DEL_ALWAYS,则表示无论如何都必须删除互斥量, 那么在删除之前,系统会把所有阻塞在该互斥量上的任务恢复。
  • (19):首先获取一下持有互斥量的任务。
  • (20):如果该互斥量被任务持有了,并且优先级也被提升了(发生优先级继承)。
  • (21):根据持有互斥量任务的状态进行分类处理。
  • (22):如果任务处于就绪状态。
  • (23):那么就将任务从就绪列表移除,然后还原任务的优先级, 互斥量控制块中的OwnerOriginalPrio成员变量保存的就是持有互斥量任务的原本优先级。
  • (24):调用OS_PrioInsert()函数将任务按照其原本的优先级插入优先级列表中。
  • (25):将任务重新插入就绪列表。
  • (26):如果任务处于延时状态、被挂起状态或者是延时中被挂起状态, 就直接将任务的优先级恢复即可,并不用进行任务列表相关的操作。
  • (27):如果任务处于无期限等待状态、有期限等待状态、 无期等待中被挂状态或者是有期等待中被挂状态,那么就调用OS_PendListChangePrio()函数改变任务在等待列表的位置,根据任务的优先级进行修改即可。
  • (28):如果状态超出预期,则返回错误类型为“任务状态非法”的错误代码。
  • (29):获取时间戳,记录一下删除的时间。
  • (30):然后根据前面cnt记录阻塞在该互斥量上的任务个数,逐个移除该互斥量等待列表中的任务。
  • (31):调用OS_PendObjDel()函数将阻塞在内核对象(如互斥量)上的任务从阻塞态恢复, 此时系统在删除内核对象,删除之后,这些等待事件的任务需要被恢复。
  • (32):系统中互斥量数目减1。
  • (33):清除互斥量中的内容。
  • (34):退出临界段,但不调度。
  • (35):调度最高优先级任务运行。
  • (36):删除互斥量完成,返回错误类型为“无错误”的错误代码。
  • (37):如果选项超出预期则返回错误类型为“任务状态非法”的错误代码。
  • (38):返回删除前互斥量等待列表中的任务数。

互斥量删除函数OSMutexDel()的使用也是很简单的,只需要传入要删除的互斥量的句柄与选项还有保存返回的错误类型即可,调用函数时,系统将删除这个互斥量。
需要注意的是在调用删除互斥量函数前,系统应存在已创建的互斥量。
如果删除互斥量时,系统中有任务正在等待该互斥量,则不应该进行删除操作, 因为删除之后的互斥量就不可用了。
删除互斥量函数OSMutexDel()的使用实例具体如下:

OS_SEM mutex;;                             //声明互斥量
OS_ERR      err;/* 删除互斥量mutex*/
OSMutexDel ((OS_MUTEX         *)&mutex,      //指向互斥量的指针
OS_OPT_DEL_NO_PEND,
(OS_ERR       *)&err);             //返回错误类型

3、获取互斥量函数OSMutexPend()

我们知道,当互斥量处于开锁的状态,任务才能获取互斥量成功,当任务持有了某个互斥量的时候,其他任务就无法获取这个互斥量,需要等到持有互斥量的任务进行释放后, 其他任务才能获取成功,任务通过互斥量获取函数来获取互斥量的所有权。
任务对互斥量的所有权是独占的,任意时刻互斥量只能被一个任务持有,如果互斥量处于开锁状态, 那么获取该互斥量的任务将成功获得该互斥量,并拥有互斥量的使用权;
如果互斥量处于闭锁状态,获取该互斥量的任务将无法获得互斥量,任务将被挂起,在任务被挂起之前, 会进行优先级继承,如果当前任务优先级比持有互斥量的任务优先级高,那么将会临时提升持有互斥量任务的优先级。
互斥量的获取函数就是OSMutexPend(),其源码具体如下:

void  OSMutexPend (OS_MUTEX  *p_mutex,      (1)     //互斥量指针OS_TICK    timeout,         (2)     //超时时间(节拍)OS_OPT     opt,             (3)     //选项CPU_TS    *p_ts,            (4)     //时间戳OS_ERR    *p_err)           (5)     //返回错误类型
{OS_PEND_DATA  pend_data;OS_TCB       *p_tcb;CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必须用到该宏,该宏声明和//定义一个局部变量,用于保存关中断前的 CPU 状态寄存器// SR(临界段关中断只需保存SR),开中断时将该值还原。#ifdef OS_SAFETY_CRITICAL//如果启用(默认禁用)了安全检测if (p_err == (OS_ERR *)0)           //如果错误类型实参为空{OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数return;                         //返回,不继续执行}
#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u//如果启用了中断中非法调用检测if (OSIntNestingCtr > (OS_NESTING_CTR)0)   //如果该函数在中断中被调用{*p_err = OS_ERR_PEND_ISR;               //错误类型为“在中断中等待”return;                                //返回,不继续执行}
#endif#if OS_CFG_ARG_CHK_EN > 0u//如果启用了参数检测if (p_mutex == (OS_MUTEX *)0)        //如果 p_mutex 为空{*p_err = OS_ERR_OBJ_PTR_NULL;     //返回错误类型为“内核对象为空”return;                          //返回,不继续执行}switch (opt)                         //根据选项分类处理{case OS_OPT_PEND_BLOCKING:       //如果选项在预期内case OS_OPT_PEND_NON_BLOCKING:break;default:                         //如果选项超出预期*p_err = OS_ERR_OPT_INVALID; //错误类型为“选项非法”return;                     //返回,不继续执行}
#endif#if OS_CFG_OBJ_TYPE_CHK_EN > 0u//如果启用了对象类型检测if (p_mutex->Type != OS_OBJ_TYPE_MUTEX)   //如果 p_mutex 非互斥量类型{*p_err = OS_ERR_OBJ_TYPE;              //错误类型为“内核对象类型错误”return;                               //返回,不继续执行}
#endifif (p_ts != (CPU_TS *)0)    //如果 p_ts 非空{*p_ts  = (CPU_TS  )0;    //初始化(清零)p_ts,待用于返回时间戳}CPU_CRITICAL_ENTER();                                //关中断if (p_mutex->OwnerNestingCtr == (OS_NESTING_CTR)0)(6)//如果互斥量可用{p_mutex->OwnerTCBPtr       =  OSTCBCurPtr; (7)//让当前任务持有互斥量p_mutex->OwnerOriginalPrio =  OSTCBCurPtr->Prio; (8)//保存持有任务的优先级p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)1; (9)//开始嵌套if (p_ts != (CPU_TS *)0)                         //如果 p_ts 非空{*p_ts  = p_mutex->TS;          (10)//返回互斥量的时间戳记录}CPU_CRITICAL_EXIT();                             //开中断*p_err = OS_ERR_NONE;                         //错误类型为“无错误”return;                                          //返回,不继续执行}
/* 如果互斥量不可用 */               (11)
if (OSTCBCurPtr == p_mutex->OwnerTCBPtr) //如果当前任务已经持有该互斥量{p_mutex->OwnerNestingCtr++;      (12)//互斥量嵌套数加1if (p_ts != (CPU_TS *)0)               //如果 p_ts 非空{*p_ts  = p_mutex->TS;               //返回互斥量的时间戳记录}CPU_CRITICAL_EXIT();                   //开中断*p_err = OS_ERR_MUTEX_OWNER;    (13)//错误类型为“任务已持有互斥量”return;                                //返回,不继续执行}/* 如果当前任务非持有该互斥量 */     (14)if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) //如果选择了不阻塞任务{CPU_CRITICAL_EXIT();                            //开中断*p_err = OS_ERR_PEND_WOULD_BLOCK;             //错误类型为“渴求阻塞”return;                                         //返回,不继续执行}else(15)//如果选择了阻塞任务{if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0)  //如果调度器被锁{CPU_CRITICAL_EXIT();                        //开中断*p_err = OS_ERR_SCHED_LOCKED;             //错误类型为“调度器被锁”return;                                     //返回,不继续执行}}/* 如果调度器未被锁 */                  (16)OS_CRITICAL_ENTER_CPU_EXIT();                     //锁调度器,并重开中断p_tcb = p_mutex->OwnerTCBPtr;                //获取互斥量持有任务if (p_tcb->Prio > OSTCBCurPtr->Prio)    (17)//如果持有任务优先级低于当前任务{switch (p_tcb->TaskState)           (18)//根据持有任务的任务状态分类处理{case OS_TASK_STATE_RDY:                        //如果是就绪状态OS_RdyListRemove(p_tcb);                //从就绪列表移除持有任务p_tcb->Prio = OSTCBCurPtr->Prio;      (19)//提升持有任务的优先级到当前任务OS_PrioInsert(p_tcb->Prio);      (20)//将该优先级插入优先级表格OS_RdyListInsertHead(p_tcb);      (21)//将持有任务插入就绪列表break;                                    //跳出case OS_TASK_STATE_DLY:                        //如果是延时状态case OS_TASK_STATE_DLY_SUSPENDED:           //如果是延时中被挂起状态case OS_TASK_STATE_SUSPENDED:                  //如果是被挂起状态p_tcb->Prio = OSTCBCurPtr->Prio;      (22)//提升持有任务的优先级到当前任务break;                                    //跳出case OS_TASK_STATE_PEND:                   //如果是无期限等待状态case OS_TASK_STATE_PEND_TIMEOUT:           //如果是有期限等待状态case OS_TASK_STATE_PEND_SUSPENDED:     //如果是无期限等待中被挂起状态case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:   //如果是有期限等待中被挂起状态OS_PendListChangePrio(p_tcb,       //改变持有任务在等待列表的位置OSTCBCurPtr->Prio);(23)break;                                    //跳出default:                          (24)//如果任务状态超出预期OS_CRITICAL_EXIT();                       //开中断*p_err = OS_ERR_STATE_INVALID;       //错误类型为“任务状态非法”return;                                   //返回,不继续执行}}/*阻塞任务,将当前任务脱离就绪列表,并插入节拍列表和等待列表。*/OS_Pend(&pend_data,(OS_PEND_OBJ *)((void *)p_mutex),OS_TASK_PEND_ON_MUTEX,timeout);                               (25)OS_CRITICAL_EXIT_NO_SCHED();          //开调度器,但不进行调度OSSched();                    (26)//调度最高优先级任务运行CPU_CRITICAL_ENTER();                 //开中断switch (OSTCBCurPtr->PendStatus)(27)//根据当前运行任务的等待状态分类处理{case OS_STATUS_PEND_OK:     (28)//如果等待正常(获得互斥量)if (p_ts != (CPU_TS *)0)     //如果 p_ts 非空{*p_ts  = OSTCBCurPtr->TS; //返回互斥量最后一次被释放的时间戳}*p_err = OS_ERR_NONE;   (29)//错误类型为“无错误”break;                       //跳出case OS_STATUS_PEND_ABORT:   (30)//如果等待被中止if (p_ts != (CPU_TS *)0)     //如果 p_ts 非空{*p_ts  = OSTCBCurPtr->TS; //返回等待被中止时的时间戳}*p_err = OS_ERR_PEND_ABORT;   //错误类型为“等待被中止”break;                       //跳出case OS_STATUS_PEND_TIMEOUT:  (31)//如果超时内为获得互斥量if (p_ts != (CPU_TS *)0)     //如果 p_ts 非空{*p_ts  = (CPU_TS  )0;     //清零 p_ts}*p_err = OS_ERR_TIMEOUT;      //错误类型为“超时”break;                       //跳出case OS_STATUS_PEND_DEL:     (32)//如果互斥量已被删除if (p_ts != (CPU_TS *)0)     //如果 p_ts 非空{*p_ts  = OSTCBCurPtr->TS; //返回互斥量被删除时的时间戳}*p_err = OS_ERR_OBJ_DEL;      //错误类型为“对象被删除”break;                       //跳出default:                   (33)//根据等待状态超出预期*p_err = OS_ERR_STATUS_INVALID;//错误类型为“状态非法”break;                        //跳出}CPU_CRITICAL_EXIT();                   //开中断
}
  • (1):互斥量指针。
  • (2):用户自定义的阻塞超时时间,单位为系统时钟节拍。
  • (3):获取互斥量的选项,当互斥量不可用的时候,用户可以选择阻塞或者不阻塞。
  • (4):用于保存返回等到互斥量时的时间戳。
  • (5):用于保存返回的错误类型,用户可以根据此变量得知错误的原因。
  • (6):如果互斥量可用, 互斥量控制块中的OwnerNestingCtr变量为0则表示互斥量处于开锁状态,互斥量可用被任务获取。
  • (7):让当前任务持有互斥量。
  • (8):保存一下持有互斥量任务的优先级。如果发生了优先级继承,就会用到这个变量。
  • (9):开始嵌套,这其实是将互斥量变为闭锁状态, 而其他任务就不能获取互斥量,但是本身持有互斥量的任务就拥有该互斥量的所有权,能递归获取该互斥量,每获取一次已经持有的互斥量, OwnerNestingCtr的值就会加一,以表示互斥量嵌套,任务获取了多少次互斥量就需要释放多少次互斥量。
  • (10):保存并且返回互斥量的时间戳记录,记录错误类型为“无错误”,退出,不继续执行。
  • (11):而如果任务想要获取的斥量处于闭锁状态(OwnerNestingCtr变量不为0), 那么就判断一下当前任务是否已经持有该互斥量。
  • (12):如果当前任务已经持有该互斥量,那么任务就拥有互斥量的所有权,能递归获取互斥量,那么互斥量嵌套数就加1。
  • (13):返回互斥量的时间戳记录与错误类型为“任务已持有互斥量”的错误代码,然后退出。
  • (14):如果当前任务并没有持有该互斥量,那肯定是不能获取到的, 就看看用户有没有选择阻塞任务,如果选择了不阻塞任务,那么就返回错误类型为“渴求阻塞”的错误代码,退出,不继续执行。
  • (15):而用户如果选择了阻塞任务, 就判断一下调度器是否被锁,如果调度器被锁了,就返回错误类型为“调度器被锁”的错误代码。
  • (16):如果调度器未被锁,就锁调度器,并重开中断, 至于为什么,在前面的章节就讲解过了,此处就不再重复赘述。
  • (17):获取持有互斥量的任务,判断一下当前任务与持有互斥量的任务优先级情况, 如果持有互斥量的任务优先级低于当前任务,就会临时将持有互斥量任务的优先级提升,提升到与当前任务优先级一致,这就是优先级继承。
  • (18):根据持有互斥量任务的任务状态分类处理。
  • (19):如果该任务处于就绪状态,那么从就绪列表中移除该任务,然后将该任务的优先级到与当前任务优先级一致。
  • (20):将该优先级插入优先级表格。
  • (21):再将该任务按照优先级顺序插入就绪列表。
  • (22):如果持有互斥量任务处于延时状态、延时中被挂起状态或者是被挂起状态, 仅仅是提升持有互斥量任务的优先级与当前任务优先级一致即可,不需要操作就绪列表。
  • (23):如果持有互斥量任务无期限等待状态、有期限等待状态、 无期限等待中被挂起状态或者是有期限等待中被挂起状态,那么就直接根据任务的优先级来改变持有互斥量任务在等待列表的位置即可。
  • (24):如果任务状态超出预期,返回错误类型为“任务状态非法”的错误代码,不继续执行。
  • (25):程序执行到这里,就表示如果需要优先级继承的就已经处理完毕了, 否则就不用优先级继承,那么可以直接调用OS_Pend()函数阻塞任务,将当前任务脱离就绪列表,并插入节拍列表和等待列表中。
  • (26):进行一次任务调度,以运行处于最高优先级的就绪任务。
  • (27):程序能执行到这里, 表示任务已经从阻塞中恢复了,但是恢复的原因有多种,需要根据当前运行任务的等待状态分类处理。
  • (28):如果任务等待正常(获得了互斥量),这是最好的结果了,任务等到了互斥量。
  • (29):保存一下获取的时间戳与错误类型为“无错误”的错误代码,就跳出switch语句继续执行。
  • (30):如果等待被中止,返回等待被中止时的时间戳与错误类型为“等待被中止”的错误代码,跳出switch语句。
  • (31):如果超时时间内未获得互斥量,就返回错误类型为“阻塞超时”的错误代码,然后跳出switch语句。
  • (32):如果互斥量已被删除, 返回互斥量被删除时的时间戳与错误类型为“对象被删除”的错误代码,跳出switch语句。
  • (33):根据等待状态超出预期,返回错误类型为“状态非法”的错误代码,退出。

至此,获取互斥量的操作就完成了,如果任务获取互斥量成功,那么在使用完毕需要立即释放,否则很容易造成其他任务无法获取互斥量, 因为互斥量的优先级继承机制是只能将优先级危害降低,而不能完全消除。
同时还需注意的是,互斥量是不允许在中断中操作的,因为互斥量特有的优先级继承机制在中断是毫无意义的, 互斥量获取函数的使用实例具体如下:

OS_MUTEX mutex;                         //声明互斥量OS_ERR      err;OSMutexPend ((OS_MUTEX  *)&mutex,                  //申请互斥量 mutex(OS_TICK    )0,                       //无期限等待
(OS_OPT     )OS_OPT_PEND_BLOCKING,  //如果不能申请到互斥量就阻塞任务(CPU_TS    *)0,                       //不想获得时间戳(OS_ERR    *)&err);                   //返回错误类

4、释放互斥量函数OSMutexPost()

任务想要访问某个资源的时候,需要先获取互斥量,然后进行资源访问,在任务使用完该资源的时候,必须要及时归还互斥量,这样别的任务才能对资源进行访问。
在前面的讲解中,我们知道,当互斥量有效的时候,任务才能获取互斥量,那么,是什么函数使得互斥量变得有效呢?
μC/OS给我们提供了互斥量释放函数OSMutexPost(), 任务可以调用该函数进行释放互斥量,表示我已经用完了,别人可以申请使用,但是要注意的是,互斥量的释放只能在任务中,不允许在中断中释放互斥量。

使用该函数接口时,只有已持有互斥量所有权的任务才能释放它,当任务调用OSMutexPost()函数时会释放一次互斥量,当互斥量的成员变量OwnerNestingCtr为0的时候, 互斥量状态才会成为开锁状态,等待获取该互斥量的任务将被唤醒。
如果任务的优先级被互斥量的优先级翻转机制临时提升,那么当互斥量被完全释放后, 任务的优先级将恢复为原本设定的优先级,其源码具体如下:

void  OSMutexPost (OS_MUTEX  *p_mutex,      (1)     //互斥量指针OS_OPT     opt,             (2)     //选项OS_ERR    *p_err)           (3)     //返回错误类型
{OS_PEND_LIST  *p_pend_list;OS_TCB        *p_tcb;CPU_TS         ts;CPU_SR_ALLOC();//使用到临界段(在关/开中断时)时必须用到该宏,该宏声明和定义一个局部变//量,用于保存关中断前的 CPU 状态寄存器 SR(临界段关中断只需保存SR)//,开中断时将该值还原。#ifdef OS_SAFETY_CRITICAL(4)//如果启用(默认禁用)了安全检测if (p_err == (OS_ERR *)0)           //如果错误类型实参为空{OS_SAFETY_CRITICAL_EXCEPTION(); //执行安全检测异常函数return;                         //返回,不继续执行}
#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u(5)//如果启用了中断中非法调用检测if (OSIntNestingCtr > (OS_NESTING_CTR)0)   //如果该函数在中断中被调用{*p_err = OS_ERR_POST_ISR;               //错误类型为“在中断中等待”return;                                //返回,不继续执行}
#endif#if OS_CFG_ARG_CHK_EN > 0u(6)//如果启用了参数检测if (p_mutex == (OS_MUTEX *)0)          //如果 p_mutex 为空{*p_err = OS_ERR_OBJ_PTR_NULL;       //错误类型为“内核对象为空”return;                            //返回,不继续执行}switch (opt)                           //根据选项分类处理{case OS_OPT_POST_NONE:             //如果选项在预期内,不处理case OS_OPT_POST_NO_SCHED:break;default:                           //如果选项超出预期*p_err =  OS_ERR_OPT_INVALID;  //错误类型为“选项非法”return;                       //返回,不继续执行}
#endif#if OS_CFG_OBJ_TYPE_CHK_EN > 0u(7)//如果启用了对象类型检测if (p_mutex->Type != OS_OBJ_TYPE_MUTEX)   //如果 p_mutex 的类型不是互斥量类型{*p_err = OS_ERR_OBJ_TYPE;              //返回,不继续执行return;}
#endifCPU_CRITICAL_ENTER();                      //关中断if(OSTCBCurPtr != p_mutex->OwnerTCBPtr)(8)//如果当前运行任务不持有该互斥量{CPU_CRITICAL_EXIT();                   //开中断*p_err = OS_ERR_MUTEX_NOT_OWNER; (9)//错误类型为“任务不持有该互斥量”return;                                //返回,不继续执行}OS_CRITICAL_ENTER_CPU_EXIT();                       //锁调度器,开中断ts          = OS_TS_GET();           (10)//获取时间戳p_mutex->TS = ts;//存储互斥量最后一次被释放的时间戳p_mutex->OwnerNestingCtr--;          (11)//互斥量的嵌套数减1if (p_mutex->OwnerNestingCtr > (OS_NESTING_CTR)0)  //如果互斥量仍被嵌套{OS_CRITICAL_EXIT();                             //解锁调度器*p_err = OS_ERR_MUTEX_NESTING;       (12)//错误类型为“互斥量被嵌套”return;                                         //返回,不继续执行}/* 如果互斥量未被嵌套,已可用 */p_pend_list = &p_mutex->PendList;          (13)//获取互斥量的等待列表if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) //如果没有任务在等待该互斥量{p_mutex->OwnerTCBPtr     = (OS_TCB  *)0;(14)//清空互斥量持有者信息p_mutex->OwnerNestingCtr = (OS_NESTING_CTR)0;(15)OS_CRITICAL_EXIT();                          //解锁调度器*p_err = OS_ERR_NONE;                (16)//错误类型为“无错误”return;                                      //返回,不继续执行}/* 如果有任务在等待该互斥量 */if (OSTCBCurPtr->Prio != p_mutex->OwnerOriginalPrio)(17)//如果当前任务的优先级被改过{OS_RdyListRemove(OSTCBCurPtr);       (18)//从就绪列表移除当前任务OSTCBCurPtr->Prio = p_mutex->OwnerOriginalPrio;(19)//还原当前任务的优先级OS_PrioInsert(OSTCBCurPtr->Prio);   (20)//在优先级表格插入这个优先级OS_RdyListInsertTail(OSTCBCurPtr);   (21)//将当前任务插入就绪列表尾端OSPrioCur     = OSTCBCurPtr->Prio;  (22)//更改当前任务优先级变量的值}p_tcb            = p_pend_list->HeadPtr->TCBPtr;        (23)    //获取等待列表的首端任务p_mutex->OwnerTCBPtr       = p_tcb;         (24)//将互斥量交给该任务p_mutex->OwnerOriginalPrio = p_tcb->Prio;(25)p_mutex->OwnerNestingCtr   = (OS_NESTING_CTR)1;   (26)//开始嵌套/* 释放互斥量给该任务 */OS_Post((OS_PEND_OBJ *)((void *)p_mutex),(OS_TCB      *)p_tcb,(void        *)0,(OS_MSG_SIZE  )0,(CPU_TS       )ts);             (27)OS_CRITICAL_EXIT_NO_SCHED();             //减锁调度器,但不执行任务调度if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0)   //如果 opt没选择“发布时不调度任务”{OSSched();                       (28)       //任务调度}*p_err = OS_ERR_NONE;                           //错误类型为“无错误”
}
  • (1):互斥量指针。
  • (2):释放互斥量的选项。
  • (3):用于保存返回的错误类型,用户可以根据此变量得知错误的原因。
  • (4):如果启用(默认禁用)了安全检测,在编译时则会包含安全检测相关的代码, 如果错误类型实参为空,系统会执行安全检测异常函数,然后返回,停止执行。
  • (5):如果启用了中断中非法调用检测,并且如果该函数在中断中被调用, 则返回错误类型为“在中断中释放”的错误代码,然后退出不继续执行。消息、信号量等内核对象可以在中断中释放, 但是唯独互斥量是不可以的,因为其具备的优先级继承特性在中断的上下文环境中毫无意义。
  • (6):如果启用了参数检测,在编译时则会包含参数检测相关的代码, 如果p_mutex参数为空,返回错误类型为“内核对象为空”的错误代码,并且退出,不执行释放互斥量操作。
  • (7):如果启用了对象类型检测,在编译时则会包含对象类型检测相关代码, 如果 p_mutex不是互斥量类型,那么返回错误类型为“对象类型有误”的错误代码,并且退出,不执行释放互斥量操作。
  • (8):程序能运行到这里,说明传递进来的参数是正确的,此时, 系统会判断一下调用互斥量释放函数的任务是否持有该互斥量,如果是则进行互斥量的释放,否则就返回错误。
  • (9):如果当前运行任务不持有该互斥量,返回错误类型为“任务不持有该互斥量”的错误代码,然后退出,不继续执行。
  • (10):获取时间戳,保存一下互斥量最后一次被释放的时间戳。
  • (11):互斥量控制块中的OwnerNestingCtr成员变量减一, 也就是互斥量的嵌套数减1,当该变量为0的时候,互斥量才变为开锁状态。
  • (12):如果互斥量仍被嵌套,也就是OwnerNestingCtr不为0, 那还是表明当前任务还是持有互斥量的,并未完全释放,返回错误类型为“互斥量仍被嵌套”的错误代码,然后退出,不继续执行。
  • (13):如果互斥量未被嵌套,已可用(OwnerNestingCtr为0), 那么就获取互斥量的等待列表保存在p_pend_list变量中,通过该变量访问互斥量等待列表。
  • (14):如果没有任务在等待该互斥量, 那么就清空互斥量持有者信息,互斥量中的OwnerTCBPtr成员变量重置为0。
  • (15):互斥量中的OwnerNestingCtr成员变量重置为0,表示互斥量处于开锁状态。
  • (16):执行到这里,表示当前任务已经完全释放互斥量了,返回错误类型为“无错误”的错误代码。
  • (17):如果有任务在等待该互斥量,那么就很有可能发生了优先级继承, 先看看当前任务的优先级是否被修改过,如果有则说明发生了优先级继承,就需要重新恢复任务原本的优先级。
  • (18):从就绪列表移除当前任务。
  • (19):还原当前任务的优先级。
  • (20):在优先级表格插入这个优先级。
  • (21):将当前任务插入就绪列表尾端。
  • (22):更改当前任务优先级变量的值。
  • (23):获取等待列表的首端任务。
  • (24):将互斥量交给该任务。
  • (25):保存一下该任务的优先级。
  • (26):互斥量的OwnerNestingCtr成员变量设置为1,表示互斥量处于闭锁状态。
  • (27):调用OS_Post()函数释放互斥量给该任务。
  • (28):进行一次任务调度。

已经获取到互斥量的任务拥有互斥量的所有权,能重复获取同一个互斥量,但是任务获取了多少次互斥量就要释放多少次互斥量才能彻底释放掉互斥量, 互斥量的状态才会变成开锁状态,否则在此之前互斥量都处于无效状态,别的任务就无法获取该互斥量。
使用该函数接口时,只有已持有互斥量所有权的任务才能释放它, 每释放一次该互斥量,它的OwnerNestingCtr成员变量就减1。
当该互斥量的OwnerNestingCtr成员变量为0时(即持有任务已经释放所有的持有操作),互斥量则变为开锁状态, 等待在该互斥量上的任务将被唤醒。
如果任务的优先级被互斥量的优先级翻转机制临时提升,那么当互斥量被释放后,任务的优先级将恢复为原本设定的优先级。
下面看看互斥量释放函数是如何使用的,具体如下:

OS_MUTEX mutex;                         //声明互斥互斥量
OS_ERR      err;
OSMutexPost ((OS_MUTEX  *)&mutex,                  //释放互斥互斥量 mutex(OS_OPT     )OS_OPT_POST_NONE,        //进行任务调度(OS_ERR    *)&err);                   //返回错误类型

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

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

相关文章

【二分查找】Leetcode 二分查找

题目解析 二分查找在数组有序可以使用,也可以在数组无序的时候使用(只要数组中的一些规律适用于二分即可) 704. 二分查找 算法讲解 当left > right的时候,我们循环结束,但是当left和right缩成一个点的时候&#x…

大数据分析与内存计算——Spark安装以及Hadoop操作——注意事项

一、Spark安装 1.相关链接 Spark安装和编程实践(Spark3.4.0)_厦大数据库实验室博客 (xmu.edu.cn) 2.安装Spark(Local模式) 按照文章中的步骤安装即可 遇到问题:xshell以及xftp不能使用 解决办法: 在…

Node.js------Express

◆ 能够使用 express.static( ) 快速托管静态资源◆ 能够使用 express 路由精简项目结构◆ 能够使用常见的 express 中间件◆ 能够使用 express 创建API接口◆ 能够在 express 中启用cors跨域资源共享 一.初识Express 1.Express 简介 官方给出的概念:Express 是基…

AcWing 312. 乌龟棋(每日一题)

原题链接:312. 乌龟棋 - AcWing题库 小明过生日的时候,爸爸送给他一副乌龟棋当作礼物。 乌龟棋的棋盘只有一行,该行有 N 个格子,每个格子上一个分数(非负整数)。 棋盘第 1 格是唯一的起点,第…

LC 222.完全二叉树的节点个数

222. 完全二叉树的节点个数 给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。 完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中…

解决沁恒ch592单片机在tmos中使用USB总线时,接入USB Hub无法枚举频繁Reset的问题

开发产品时采用了沁恒ch592,做USB开发时遇到了一个奇葩的无法枚举问题。 典型症状 使用USB线直连电脑时没有问题,可以正常使用。 如果接入某些特定方案的USB Hub(例如GL3510、GL3520),可能会出现以下2种情况&#xf…

2024年第八届人工智能与虚拟现实国际会议(AIVR 2024)即将召开!

2024年第八届人工智能与虚拟现实国际会议(AIVR 2024)将2024年7月19-21日在日本福冈举行。人工智能与虚拟现实的发展对推动科技进步、促进经济发展、提升人类生活质量等具有重要意义。AIVR 2024将携手各专家学者,共同挖掘智能与虚拟的无限可能…

【C++初阶】 vector 在OJ中的使用

前言: 🎯个人博客:Dream_Chaser 🎈博客专栏:C 📚本篇内容:只出现一次的数字 和 杨辉三角 OJ 目录 一、只出现一次的数字 题目描述: 二、杨辉三角OJ 题目描述: 一、只…

AI设计优化电机、电路与芯片?

一、AI进行电机本体设计 使用AI进行电机本体设计是一种前沿且具有潜力的方法,通过深度学习、强化学习、遗传算法等AI技术,可以实现电机设计的自动化和优化。具体应用可以包括以下几个方面: 此图片来源于网络 1. **参数优化**: …

docker + miniconda + python 环境安装与迁移(详细版)

本文主要列出从安装dockerpython环境到迁移环境的整体步骤。windows与linux之间进行测试。 简化版可以参考:docker miniconda python 环境安装与迁移(简化版)-CSDN博客 目录 一、docker 安装和测试 二、docker中拉取miniconda&#xff…

vscode 连接远程服务器 服务器无法上网 离线配置 .vscode-server

离线配置 vscode 连接远程服务器 .vscode-server 1. .vscode-server下载 使用vscode连接远程服务器时会自动下载配置.vscode-server文件夹,如果远程服务器无法联网,则需要手动下载 1)网址:https://update.code.visualstudio.com…

ICP备案工信部短信核验怎么看是否成功?

备案短信核验怎么看是否成功?在工信部官网输入6位短信验证码、手机号和身份证号后,点击提交,会返回尊敬的ICP用户: 您的短信核验已全部完成,该请求将提交管局审核。如下图: 尊敬的ICP用户: 您的短信核验已全…

ArcGis研究区边界提取

ArcGis研究区边界提取 *0* 引言*1* 有的步骤0 引言 GRACE数据处理前要先确定研究范围,而大多情况下所选的研究区都是有特殊意义的,比如常年干旱、经济特区、降水丰富等,这些区域往往有精确的边界,那就要从大的区块中将研究范围抠出来,获取相应坐标,以量化区域重力变化。那…

蓝桥集训之斐波那契数列

蓝桥集训之斐波那契数列 核心思想&#xff1a;矩阵乘法 将原本O(n)的递推算法优化为O(log2n) 构造1x2矩阵f和2x2矩阵a 发现f(n1) f(n) * a 则f(n1) f(1) * an可以用快速幂优化 #include <iostream>#include <cstring>#include <algorithm>using na…

白嫖 kimi.ai 的 API 接口,给这个开源项目点赞!

Kimi 是当前国内相当火爆的 AI 产品&#xff0c;输出结果和使用体验都非常不错。 Kimi 开放了 API 接口&#xff0c;新用户注册后会免费赠送 15 元额度。 Kimi API 的网址&#xff1a; platform.moonshot.cn/console 这是光明正大的白嫖方式&#xff0c;一定不要错过哦。 如…

【机器学习300问】61、逻辑回归与线性回归的异同?

本文讲述两个经典机器学习逻辑回归&#xff08;Logistic Regression&#xff09;和线性回归&#xff08;Linear Regression&#xff09;算法的异同&#xff0c;有助于我们在面对实际问题时更好的进行模型选择。也能帮助我们加深对两者的理解&#xff0c;掌握这两类基础模型有助…

算法设计与分析实验报告c++实现(排序算法、三壶谜题、交替放置的碟子、带锁的门)

一、实验目的 1&#xff0e;加深学生对分治法算法设计方法的基本思想、基本步骤、基本方法的理解与掌握&#xff1b; 2&#xff0e;提高学生利用课堂所学知识解决实际问题的能力&#xff1b; 3&#xff0e;提高学生综合应用所学知识解决实际问题的能力。 二、实验任务 1、 编…

计算机网络学习

OSI 七层模型 物理层&#xff08;Physical Layer&#xff09; 功能&#xff1a;处理与电气或物理规范的接口有关的细节&#xff0c;如电缆类型、电信号传输和接收、网络设备的物理特性等。设备&#xff1a;包括网线、光纤、集线器等。 数据链路层&#xff08;Data Link Laye…

AcWing---公约数---最大公约数

4199. 公约数 - AcWing题库 思路&#xff1a; 最大整数x一定是最大公约数的因数&#xff0c;所以先用__gcd(a,b)求出a和b的最大公因数&#xff0c;再用O(log(n))的算法求出最大公因数的因数&#xff0c;放到vector中&#xff0c;并将vector排序。利用STL中的upper_bound(res.…

Star GAN论文解析

论文地址&#xff1a;https://arxiv.org/pdf/1912.01865v1.pdf https://openaccess.thecvf.com/content_cvpr_2018/papers/Choi_StarGAN_Unified_Generative_CVPR_2018_paper.pdf 源码&#xff1a;stargan项目实战及源码解读-CSDN博客 1. 概述 在传统方法中&#x…