使用中断开关实现全局变量互斥访问

  最近在STM32F429平台上实现一套主从机串口库,在开发过程中,出现偶发性丢帧问题,反复核对关键代码,均未发现任何问题,一筹莫展。按照经验第一反应就是互斥访问导致的脏数据问题,但苦于无法锁定问题,因为只有在串口大量数据收发时,才出现偶发性丢帧,无法采取在线调试锁定问题,极其难以抓取。为了能够尽快找到问题关键采取了最费力的办法:

  1. 锁定问题代码,对所有全局变量互斥访问代码逐一注释,同时检测注释后是否停止丢帧:锁定问题代码位置;
  2. 在问题代码处添加调试代码,通过串口重定向打印相关全局变量;

  虽然方法费时费力,但很快有了突破:打印出来的全局变量仅反复的进行加0操作,其未做任何改变,但仍发生丢帧,由此推论:串口丢帧是由于全局变量互斥访问引起的可能性极大。

  解决方法:1、使用中断开关,在进行互斥访问前关闭中断,完成后再开启中断;2、使用LDREX/STREX指令;

  为了最快地解决问题,先暂时采用方法一(以下是部分代码):

void uart_it_sw(FunctionalState state)
{
    USART_ITConfig(USART, USART_IT_RXNE, state);
}

void USART1_IRQHandler(void)
{
  uint8_t ucTemp;
	if(USART_GetITStatus(USART,USART_IT_RXNE)!=RESET)
	{
		ucTemp = USART_ReceiveData( USART );
		push(ucTemp);
	}
}	

static int front=0;
static int rear=0;
static int count=0;

void push(unsigned char tmp)
{
    recv_buf[rear]=tmp;
    rear++;
    rear%=MAX_QUEUE_LEN;

    if (count==MAX_QUEUE_LEN)
    {
        front++;
        front%=MAX_QUEUE_LEN;
    }
    else
    {
        count++;
    }
}

void pop(int len)
{
    // if (len>0)
    {
        if (len>count)
        {
            len=count;
        }
        uart_it_sw(DISABLE); //互斥访问前关闭串口中断
        front+=len;
        front%=MAX_QUEUE_LEN;
        count-=len;
        uart_it_sw(ENABLE); //互斥访问结束重新打开串口中断
    }
}

void empty(void)
{
    uart_it_sw(DISABLE);
    front=0;
    rear=0;
    count=0;
    uart_it_sw(ENABLE);
}

  结果:在开启互斥访问中断开关后,长时间大量测试下均未发生丢帧。  

  总结:如何锁定和确定问题和解决问题的最终方法一样的重要;其次大胆猜测,用后验逻辑去解决问题也不失为一种解决问题的好思路。

  

  

原文地址:https://www.cnblogs.com/randyjang/p/8476043.html

时间: 2024-10-24 21:13:01

使用中断开关实现全局变量互斥访问的相关文章

进程对临界资源的互斥访问

临界资源与临界区 临界资源(critical resource):一次只能供一个进程使用的资源.   如:硬件有打印机等,软件有变量,磁盘文件(写入的时候). 临界区(critical section):把进程中访问临界资源的那段代码成为临界区. 为了实现临界资源的互斥访问,只要做到进程互斥地进去自己的临界区,便可以实现进程对临界资源的互斥访问. 同步机制 为实现各进程互质地访问自己的临界区,操作系统需要同步机制来协调各进程的运行. 1.同步机制的规则 (1)空闲让进:当无进程处于临界区,表明临

浅析Redis实现lock互斥访问资源

Redis是当前很流行的一种开源键值数据库.目前睿思的后台架构在数据库层采用了Redis和MySQL组合的形式,其中Redis主要用来存储状态信息(比如当前种子的peer)和读写频繁的数据.Redis完全运行在内存之上,无lock设计,速度非常快!通过实测,在睿思服务器上读写速度达到3万次/s. 在高并发的应用中,很多时候我们需要对某些资源进行竞争访问,比如在很多人下载一个热门资源,就可能存在很多请求去修改某个资源的peer信息(就是保存了当前保种人的ip地址和端口号),需要保证某个请求修改pe

单实例模式和互斥访问

场景说明:在实际的应用开发中,很多人没有注意到一点:在生成单实例的过程中,如果由线程去创建对象的实例,有可能在第一次检测到对象不存在的情况下,准备创建对象,此时由于多线程的缘故,恰巧当前线程被挂起,另一个线程同样执行到这个语句,于是创建一个对象,另一个线程冲睡眠中被唤醒,于是执行了创建对象,现在就有两个对象,完全背离了单实例的设计模式, 解决方法: 1)在主线程还没有创建多线程的时候,创建单实例,但是这里有一个问题:就不会达到延时加载的效果,变成了急剧加载,也就是说预先加载了对象,可能这个对象根

单片机中断全局变量保护方法

首先要明白这几个知识点:关键字volatile的使用,原子操作,临界区的使用.明白的直接跳到文中的4.全局变量的使用及保护处查看. 1.关键字volatile 关键字volatile用于告诉编译器,说明被修身的变量可能会被意想不到地改变,防止编译器对代码进行优化. 比如如下程序: 1 ucNms=0x65;2 ucNms=0x66;3 ucNms=0x67;4 ucNms=0x68; 上述4条语句,如果变量在声明的时候(unsigned char ucNms;)没有使用volatile,那么编译

信号量、互斥锁,读写锁和条件变量的区别

信号量强调的是线程(或进程)间的同步:“信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都 在sem_wait的时候,就阻塞在那里).当信号量为单值信号量是,也可以完成一个资源的互斥访问.有名信号量:可以用于不同进程间或多线程间的互斥与同步 创建打开有名信号量 sem_t *sem_open(const char *name, int oflag); sem_t *sem_open(const char *name, int oflag

线程同步(互斥锁与信号量的作用与区别)

“信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在 哪里).而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这 个资源.比如对全局变量的访问,有时要加锁,操作完了,在解锁.有的时候锁和信号量会同时使用的” 也就是说,信号量不一定是锁定某一个资源,而是流程上的概念,比如:有A,B两个线程,B线程要等A线程完成某一任务以后

互斥锁的实现

http://blog.csdn.net/hzhzh007/article/details/6532988 “ 信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在sem_wait的时候,就阻塞在 那里).而互斥锁是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这 个资源.比如对全局变量的访问,有时要加锁,操作完了,在解锁.有的时候锁和信号量会同时使用的” 也

RTX——第19章 SVC 中断方式调用用户函数(后期补历程)

本章节为大家讲解如何采用 SVC 中断方式调用用户函数. 当用户将 RTX 任务设置为工作在非特权级模式时,任务中是不允许访问特权级寄存器的,这个时候使用 SVC 中断,此问题就迎刃而解了. SVC 功能介绍SVC 用于产生系统函数的调用请求.例如,操作系统通常不让用户程序直接访问硬件,而是通过提供一些系统服务函数,让用户程序使用 SVC 发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件.因此,当用户程序想要控制特定的硬件时,它就要产生一个 SVC 异常,然后操作系统提供的SVC

Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock

ReentrantLock介绍 ReentrantLock是一个可重入的互斥锁,又被称为"独占锁". 顾名思义,ReentrantLock锁在同一个时间点只能被一个线程锁持有:而可重入的意思是,ReentrantLock锁,可以被单个线程多次获取.ReentrantLock分为"公平锁"和"非公平锁".它们的区别体现在获取锁的机制上是否公平."锁"是为了保护竞争资源,防止多个线程同时操作线程而出错,ReentrantLock在