解决程序堵塞的优化方法(二)

简介: 解决程序堵塞的优化方法(二)

  本文链接上篇继续叙述,如果没有看到看一篇的,大家可以点击传送门观看。4edc953e2c684bbe819ffa954c899c08.png

作者:良知犹存

转载授权以及围观:欢迎添加wx:Allen-Iverson-me-LYN

总述      

1.通过运用RTOS,线程里面调用系统提供的延时等函数,实现解决阻塞。

2.全局变量方法,定时器计数条件判断替代延时。

3.使用状态机方式,分解动作,替代延时实现。

4.使用链表式,与第三种相似。

三、 状态机法

 状态机执行与全局变量的区别在于,状态机的方法是更进一层的定时操作,可以通过状态机在主循环或者触发函数实现多个动作的延时操作。

    状态机中大致会分为两类延时替代操作,一种注重多个动作的延时,一种叫精确时间的延时。第一种情况经常会在一些需要双方有来有往的应答操作出现,而后一种出现在明确延时操作过程中。接下来我们展示一下代码风格吧。


/*堵塞型的代码*/
void clogged(void)
{
  taskfun1();
  delay(500);
  taskfun2();
  delay(100);
  taskfun3();
  delay(20);  
}
int main(int argc,char** argv)
{
   SystemInit();
   while(1)
   {
     clogged();
     taskfun();/*此段代码执行的时候会被堵塞*/
   }
}

1.注重动作的状态机

/*注重分解动作的状态机*/
void TIM_IRQ(void)/*定时器中断服务函数*/
{
  FSMtimer ++;/*设置合适的中断时间间隔*/
}
static u32 FSMtimer = 0,LastFSMtimer = 0;/*用来计时变量*/
static u8  FSMSta   = 0;/*设置状态的工作步骤的变量*/
void actionFSM(void)
{
  switch(FSMSta)
  {
    case 0:   
      taskfun1();
      FSMSta   = 1;
      break;
    case 1:   
      taskfun2();
      FSMSta   = 2;
      break;
    case 2:
      taskfun3();
      FSMSta   = 3;       
      break;
    case 3:
      if(FSMtimer - LastFSMtimer >100 )/*定时判断完成任务*/
      {
        taskfun4();
        FSMSta   = 4;        
      }
      else
      {
        taskfun5();
        FSMSta   = 1;/*条件判断出现问题,实现动作跳转,进行动作重复*/          
      }
      break;   
    case 4:
      taskidle();/*状态机的状态执行完成可以进行空闲任务*/  
      break;   
}
int main(int argc,char** argv)
{
   SystemInit();
   FSMSta   = n;/*初始化设置状态机的起始步*/
   while(1)
   {
     actionFSM();/*替换效果如下*/
     taskfun();/*此段代码执行的时候会被堵塞*/
   }
}

2.注重精确延时固定动作的状态机

/*延时操作的结构体*/
__packed typedef struct{
  bool IsFSM_start;/*延时计数的标志*/
  u8   FSM_Sta:7;/*状态机执行的状态*/
  u32  FSM_target;/*延时定时的目标值*/
  u32  FSM_count;/*状态机用来在计数器中累加计时的变量*/
  u8   FSM_flag;/*状态机part的标志*/
}DelayTypeDef;
DelayTypeDef DelayFSM;
/*定时中断服务函数*/
void TIM_IRQ(void)
{
  if(DelayFSM.FSM_flag==1)/*执行状态机部分标志*/
  {
    if(DelayFSM.IsFSM_start== 1)/*动作执行代码,为零则不进入计时操作*/
    {
      (DelayFSM.FSM_count<DelayFSM.FSM_target)?
      (DelayFSM.FSM_count++):
      (DelayFSM.IsFSM_start=0,DelayFSM.FSM_Sta++);/*IsFSM_start==0 
                                                    进入状态机执行*/
    }
  }
}
u8 taskfun(void)
{
  if(DelayFSM.FSM_flag==0)/*初始化代码部分*/
  {
    DelayFSM.FSM_flag= 1;/*设置状态机flag为1 ,执行下一部分程序*/
    DelayFSM.IsFSM_start= 0;/*开始状态机*/
    DelayFSM.FSM_Sta= 1;/*初始化第一步*/
  }
  else if (DelayFSM.FSM_flag==1)
  {
    if(DelayFSM.IsFSM_start== 0)
    {
      switch(DelayFSM.FSM_Sta)
      {
        case 0x01:
          DelayFSM.IsFSM_start= 1;/*IsFSM_start==1 进入计时器计时*/
          DelayFSM.FSM_count= 0; /*计数器清零*/ 
          DelayFSM.FSM_target= 1000;/*设置计时的目标时间为
                                   1000个定时器触发时间间隔*/
          taskfun1();/*任意任务函数*/
        break;
        case 0x02:
          DelayFSM.IsFSM_start= 1;/*注释如上*/
          DelayFSM.FSM_count= 0;  /*注释如上*/
          DelayFSM.FSM_target= 500;/*目标值为500基数*/
          taskfun2();/*任意任务函数*/
        break;    
        case 0x03:
          DelayFSM.IsFSM_start= 0;/*状态机完成状态 start清零*/
          DelayFSM.FSM_Sta= 0; /*清零代表状态机将进入空闲模式*/
          DelayFSM.FSM_target= 0;/*目标值设置位零*/
          DelayFSM.FSM_flag= 3;/*随意赋值,这个值与你在主程序的判断,
          重启状态机的标记相关,可看main中程序*/
          taskfun3();/*任意任务函数*/
        break;
        default:
        break;
      }
    }
   }
  else
       return  0;
   return  1;
}
int main(int argc,char** argv)
{
    SystemInit();
    while(1)
    {
      taskfun();/*状态机执行*/
      if (DelayFSM.flag==3)/*重复使用次状态机*/
      {
         DelayFSM.flag = 0; 
      }   
    }
}

这就是我分享的通过状态机实现的解决堵塞方法,里面代码是实践过的,如果大家有什么更好的思路,欢迎分享交流哈

四、 链表法

      通过上面结构体状态机程序,我们知晓通过一些特定的延时程序等待,配合状态机可以替换很多的队列式延时。可是通过结构体 定义的时候,如果需要很多处的延时阻塞替换,则会产生很多的延时变量,这个时候需要管理很多不同名称的变量,这样容易造成混乱。所以我们可以选择链表使用,链表定义好head之后,只要模式一样数据变量,我们只需要添加一个节点即可。

注:这里使用链表是单链表,双链表暂且不需要用到。链表的使用方法我是参考一位博主的文章而使用的,如果需要大家也可以去欣赏他的文章,这里是传送门

#define ONCE  0
#define CYCLE 1
typedef struct Delay_TIMER
{
  bool                  mode;/*设置的模式 0 单次计时  1 循环计时*/
  bool                  isActivate;/*判定是否需要启动定时*/
  volatile u32          cnt;/*计数器*/
  u32                   target;/*目标数值*/
  struct Delay_TIMER*   next;/*下一个节点*/
}Delay_TIMER_t;
static struct Delay_TIMER *head = NULL;/*定义链表的头*/
/* 定时器中断服务程序*/
void TIM_ISR(void)
{
  struct Delay_TIMER *t = head;
  if (t == NULL)
    return;
  while(t != NULL)
  {
    if (t->isActivate == true)
      t->cnt++;/*计数器定时累加*/
    t = t->next;
  }
}
/*插入一个需要定时的链表节点,并初始化成员变量*/
void Insert_delay_node(Delay_TIMER_t *node,bool mode,uint32_t target)
{
  struct Delay_TIMER *t = head;  
  node->isActivate = true;/*设置为开*/
  node->mode       = mode;/*模式支持自己设置*/
  node->cnt        = 0;
  node->target     = target;/*设置目标时长数值*/
  node->next       = NULL;
  if (head == NULL)
  {
    head = node;
    return;
  }
  while(t->next != NULL )
  {
    if (t == node) return; 
    t = t->next;
  }
  t->next = node;
}
/*删除不需要使用的延时节点*/
void Delete_delay_node(Delay_TIMER_t *node)
{
  struct Delay_TIMER  *p = head,*t = head;
  if (head == node)
  {
    head = node->next;
    return;
  }
  while(t->next != NULL )/*当需要删除尾部最后一个节点的时候,
                          tail->next == NULL,这个时候循环跳出,节点无法删除*/
  {
    if (t == node)      /*删除节点*/
    {
      p->next = node->next;/*node->next == NULL;*/
      node->next = NULL;
    }
    else
    {
      p = t;
      t = t->next;/* t = p->next;*/
    }
  }
  if(t->next == NULL && head != node)/*删除最后一个节点*/
  {
      p->next = NULL;/*尾部最后一个节点直接置NULL*/
  }
}
/*查询软件计时器是否超时*/
bool Is_delay_timer_Out(Delay_TIMER_t *node)
{
  bool res = false;
  if (node->cnt  >= node->target)
  {
    res = true;
    if (node->mode == CYCLE)
    {
      node->cnt        = 0;  
      node->isActivate = true;
    }else
      node->isActivate = false;
  }  
  return res;   
}
/*主程序*/
int main(int argc,char** argv)
{
  SystemInit();
  u8 mode = 0;/*单次模式*/
  static u8 STA = 1;/*设置状态机初始step*/
  static Delay_TIMER_t task_delay;  
  Insert_delay_node(task_delay,mode,1000);/*初始化节点,设置为单次模式,
  计时目标为1000个计数间隔*/
  while(1)
  {
    switch(STA)
    {
      case 1:
        taskfun1();
        STA = 2;
        break;
      case 2:/*延时等待状态*/
        if (Is_delay_timer_Out(&task_delay) == true)
          STA = 1;      
        break;
    }
  }
}
目录
相关文章
|
21天前
|
Arthas Java 应用服务中间件
我的程序突然罢工了|深入探究HSF调用异常,从死锁到活锁的全面分析与解决
本文详细记录了作者在处理HSF调用异常问题的过程中,从初步怀疑死锁到最终发现并解决活锁问题的全过程。
213 13
|
2月前
|
数据采集 存储 NoSQL
提高爬虫性能的 5 个关键技巧:从并发到异步执行
本文介绍了提高网络爬虫性能的五个关键技巧:并发请求、异步执行、使用代理IP、限制请求频率与休眠时间、优化数据提取与存储。结合拼多多的实际案例,展示了如何通过这些技术优化爬虫效率,确保数据采集的高效性和稳定性。
262 0
|
5月前
|
机器学习/深度学习 Java 数据挖掘
线程操纵术之更优雅的并行策略问题之并发和并行有区别问题如何解决
线程操纵术之更优雅的并行策略问题之并发和并行有区别问题如何解决
|
5月前
|
安全
线程操纵术并行策略问题之ForkJoinTask提交任务的问题如何解决
线程操纵术并行策略问题之ForkJoinTask提交任务的问题如何解决
|
6月前
|
缓存 算法 Java
深入解析线程上下文切换的原理与优化策略
深入解析线程上下文切换的原理与优化策略
581 0
|
7月前
|
监控 安全
线程死循环是多线程应用程序开发过程中一个难以忽视的问题,它源于线程在执行过程中因逻辑错误或不可预见的竞争状态而陷入永久运行的状态,严重影响系统的稳定性和资源利用率。那么,如何精准定位并妥善处理线程死循环现象,并在编码阶段就规避潜在风险呢?谈谈你的看法~
避免线程死循环的关键策略包括使用同步机制(如锁和信号量)、减少共享可变状态、设置超时、利用监控工具、定期代码审查和测试、异常处理及设计简洁线程逻辑。通过这些方法,可降低竞态条件、死锁风险,提升程序稳定性和可靠性。
106 0
|
缓存 Java 容器
【并发技术10】线程并发库的使用
【并发技术10】线程并发库的使用
|
Java 编译器 调度
锁的优化过程
锁的优化过程
|
网络协议 PHP 数据库
浅谈非堵塞程序的理解
当程序需要发送网络请求或者从磁盘中读取文件等IO操作时 CPU发出指令,然后信号经过总线到达网卡或者磁盘 然后拿到数据,再经过总线到达主存中,CPU继续对主存中的数据进行操作。
162 0
浅谈非堵塞程序的理解
|
调度
解决程序堵塞的优化方法(一)
解决程序堵塞的优化方法(一)
288 0
解决程序堵塞的优化方法(一)