中断处理

FreeRTOS优化与错误排查方法

时间秒杀一切 提交于 2019-12-01 10:20:44
写在前面 主要是为刚接触 FreeRTOS 的用户指出那些新手通常容易遇到的问题。这里把最主要的篇幅放在栈溢出以及栈溢出j检测上,因为栈相关的问题是初学者遇到最多的问题。 printf-stdarg.c 当调用 C 标准库 的函数时,栈空间使用量可能会急剧上升,特别是 IO 与字符串处理函数,比如 sprintf()、printf()等。在 FreeRTOS 源码包中有一个名为 printf-stdarg.c 的文件。这个文件实现了一个栈效率优化版的小型 sprintf()、printf(),可以用来代替标准 C 库函数版本。在大多数情况下,这样做可以使得调用 sprintf()及相关函数的任务对栈空间的需求量小很多。 可能很多人都不知道freertos中有这样子的一个文件,它放在第三方资料中,路径为“ FreeRTOSv9.0.0\FreeRTOS-Plus\Demo\FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC ”,我们发布工程的时候就无需依赖 C 标准库 ,这样子就能减少栈的使用,能优化不少空间。 该文件源码(部分): static int print( char **out, const char *format, va_list args ) { register int width, pad; register int pc = 0;

从0开始学FreeRTOS-(任务调度)-4

杀马特。学长 韩版系。学妹 提交于 2019-12-01 10:19:26
大家晚上好,我是杰杰,最近挺忙的,好久没有更新了,今天周末就吐血更新一下吧! # 前言 `FreeRTOS`是一个是实时内核,任务是程序执行的最小单位,也是调度器处理的基本单位,移植了`FreeRTOS`,则避免不了对任务的管理,在多个任务运行的时候,任务切换显得尤为重要。而任务切换的效率会决定了系统的稳定性与效率。 `FreeRTOS`的任务切换是干嘛的呢,`rtos`的实际是永远运行的是具有最高优先级的运行态任务,而那些之前在就绪态的任务怎么变成运行态使其得以运行呢,这就是我们`FreeRTOS`任务切换要做的事情,它要做的是找到最高优先级的就绪态任务,并且让它获得cpu的使用权,这样,它就能从就绪态变成运行态,这样子,整个系统的实时性就会很好,响应也会很好,而不会让程序阻塞卡死。 要知道怎么实现任务切换,那就要知道任务切换的机制,在不同的`cpu(mcu)`中,触发的方式可能会不一样,现在是以Cortex-M3为例来讲讲任务的切换。为了大家能看懂本文,我就抛转引玉一下,`引用《Cortex-M3权威指南-中文版》的部分语句(如涉及侵权,请联系杰杰删除)` # SVC 和 PendSV SVC(系统服务调用,亦简称系统调用)和 `PendSV`(`Pended System Call`,可悬起系统调用),它们多用于在操作系统之上的软件开发中。`SVC`

多线程基础体系知识清单

三世轮回 提交于 2019-12-01 07:48:33
前言 本文会介绍Java中多线程与并发的基础,适合初学者食用。 线程与进程的区别 在计算机发展初期,每台计算机是串行地执行任务的,如果碰上需要IO的地方,还需要等待长时间的用户IO,后来经过一段时间有了批处理计算机,其可以批量串行地处理用户指令,但本质还是串行,还是不能并发执行。 如何解决并发执行的问题呢? 于是引入了进程的概念,每个进程独占一份内存空间,进程是内存分配的最小单位,相互间运行互不干扰且可以相互切换,现在我们所看到的多个进程“同时"在运行,实际上是进程高速切换的效果。 那么有了线程之后,我们的计算机系统看似已经很完美了,为什么还要进入线程呢?如果一个进程有多个子任务,往往一个进程需要逐个去执行这些子任务,但往往这些子任务是不相互依赖的,可以并发执行,所以需要CPU进行更细粒度的切换。所以就引入了线程的概念,线程隶属于某一个进程,它共享进程的内存资源,相互间切换更快速。 进程与线程的区别: 进程是资源分配的最小单位,线程是CPU调度的最小单位。所有与进程相关的资源,均被记录在PCB中。 线程隶属于某一个进程,共享所属进程的资源。线程只由堆栈寄存器、程序计数器和TCB构成。 进程可以看作独立的应用,线程不能看作独立的应用。 进程有独立的地址空间,相互不影响,而线程只是进程的不同执行路径,如果线程挂了,进程也就挂了。所以多进程的程序比多线程程序健壮,但是切换消耗资源多。

ReentrantLock

百般思念 提交于 2019-12-01 07:19:37
在了解ReentrantLock之前,我们首先回忆一下 synchronized ,synchronized是java内置的关键字,锁的获取和释放都是由jvm实现,因此用户就不需要显示的去释放锁,是一种独占的加锁方式,但是虽然方便,也有一定的弊端: 1.当线程尝试获取锁的时候,如果获取不到锁会一直阻塞,这个阻塞的过程,用户无法控制 2.如果获取锁的线程进入休眠或者阻塞,除非当前线程异常,否则其他线程尝试获取锁必须一直等待 接下来我们还需要了解几个相关的概念: 可重入锁 :可重入锁是指同一个线程可以多次获得同一把锁; ReentrantLock和关键字Synchronized都是可重入锁 。 可中断锁 :可中断锁时只线程在获取锁的过程中,是否可以相应线程中断操作。 synchronized是不可中断的 , ReentrantLock是可中断的 。 公平锁和非公平锁 :公平锁是指多个线程尝试获取同一把锁的时候,获取锁的顺序按照线程到达的先后顺序获取,而不是随机插队的方式获取。 synchronized是非公平锁 ,而 ReentrantLock是两种都可以实现,不过默认是非公平锁 1.ReentrantLock的使用方式 public class Demo { ReentrantLock lock = new ReentrantLock(); public static int num

一、线程基础

泄露秘密 提交于 2019-12-01 07:10:26
线程基础 一、认识java里的线程 1)java里的程序天生都是多线程的 public static void main(String[] args) { ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false); for (ThreadInfo threadInfo : threadInfos) { System.out.println("["+threadInfo.getThreadId()+"]"+" "+threadInfo.getThreadName()); } } /** * [6] Monitor Ctrl-Break * [5] Attach Listener * [4] Signal Dispatcher * [3] Finalizer * [2] Reference Handler * [1] main */ 可以看出我们只是启动了一个main方法,java虚拟机也给我们启动了6个线程,所以我们说java里的程序天生都是多线程的 二、java中启动多线程的三种方式 以下内容学习自:https://blog.csdn.net/m0_38075425

一文教你安全的关闭线程池

雨燕双飞 提交于 2019-12-01 06:40:13
上篇文章 ShutdownHook- Java 优雅停机解决方案 提到应用停机时需要释放资源,关闭连接。对于一些定时任务或者网络请求服务将会使用线程池,当应用停机时需要正确安全的关闭线程池,如果处理不当,可能造成数据丢失,业务请求结果不正确等问题。 关闭线程池我们可以选择什么都不做,JVM 关闭时自然的会清除线程池对象。当然这么做,存在很大的弊端,线程池中正在执行执行的线程以及队列中还未执行任务将会变得极不可控。所以我们需要想办法控制到这些未执行的任务以及正在执行的线程。 线程池 API 提供两个主动关闭的方法 ThreadPoolExecutor#shutdownNow 与 ThreadPoolExecutor#shutdown ,这两个方法都可以用于关闭线程池,但是具体效果却不太一样。 线程池的状态 在说线程池关闭方法之前,我们先了解线程池状态。 线程池状态关系图如下: 从上图我们看到线程池总共存在 5 种状态,分别为: RUNNING :线程池创建之后的初始状态,这种状态下可以执行任务。 SHUTDOWN :该状态下线程池不再接受新任务,但是会将工作队列中的任务执行结束。 STOP : 该状态下线程池不再接受新任务,但是不会处理工作队列中的任务,并且将会中断线程。 TIDYING :该状态下所有任务都已终止,将会执行 terminated() 钩子方法。 TERMINATED

进程上下文与中断上下文

对着背影说爱祢 提交于 2019-12-01 06:39:45
进程上下文与中断上下文 https://www.cnblogs.com/alantu2018/p/8461094.html 有进程上下文切换 也有 模式切换 不通的切换的损耗是不一样的 上下文切换时 堆栈信息 寄存器信息 用户信息都得切换 其实代价还是很高的. 1、前言   最近在学习linux内核方面的知识,经常会看到用户空间与内核空间及进程上下文与中断上下文。看着很熟悉,半天又说不出到底是怎么回事,有什么区别。看书过程经常被感觉欺骗,似懂非懂的感觉,很是不爽,今天好好结合书和网上的资料总结一下,加深理解。 2、用户空间与内核空间      我们知道现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操心系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核,保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享

Linux被中断的系统调用

▼魔方 西西 提交于 2019-12-01 05:04:49
慢系统调用,指的是可能永远无法返回,从而使进程永远阻塞的系统调用,比如无客户连接时的accept、无输入时的read都属于慢速系统调用。 在Linux中,当阻塞于某个慢系统调用的进程捕获一个信号,则该系统调用就会被中断,转而执行信号处理函数,这就是被中断的系统调用。 然而,当信号处理函数返回时,有可能发生以下的情况: 如果信号处理函数是用signal注册的,系统调用会自动重启,函数不会返回 如果信号处理函数是用sigaction注册的 默认情况下,系统调用不会自动重启,函数将返回失败,同时errno被置为EINTR 只有中断信号的SA_RESTART标志有效时,系统调用才会自动重启 下面我们编写代码,分别验证上述几种情形,其中系统调用选择read,中断信号选择SIGALRM,中断信号由alarm产生。 使用signal #include <stdio.h> #include <signal.h> #include <unistd.h> #include <errno.h> void handler(int s) { printf("read is interrupt by signal handler\n"); return; } int main() { char buf[10]; int nread = 0; signal(SIGALRM, handler); alarm(2)

java并发-ReentrantLock的lock和lockInterruptibly的区别

跟風遠走 提交于 2019-12-01 01:44:52
ReentrantLock的加锁方法Lock()提供了无条件地轮询获取锁的方式,lockInterruptibly()提供了可中断的锁获取方式。这两个方法的区别在哪里呢?通过分析源码可以知道lock方法默认处理了中断请求,一旦监测到中断状态,则中断当前线程;而lockInterruptibly()则直接抛出中断异常,由上层调用者区去处理中断。 1 lock操作 lock获取锁过程中,忽略了中断,在成功获取锁之后,再根据中断标识处理中断,即selfInterrupt中断自己。 acquire操作源码如下: /** *默认处理中断方式是selfInterrupt */ public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } acquireQueued,在for循环中无条件重试获取锁,直到成功获取锁,同时返回线程中断状态。该方法通过for循正常返回时,必定是成功获取到了锁。 /** *无条件重试,直到成功返回,并且记录中断状态 */ final boolean acquireQueued(final Node node, int arg) { boolean failed = true;

协作,才能更好的中断线程

前提是你 提交于 2019-12-01 01:16:49
协作,才能更好的中断线程 聊起中断,大家可能最熟悉的例子就是线程休眠。下面就是一个线程休眠的 demo,在这个例子中,当我们调用 sleep 方法,该方法将会抛出一个需要捕获的中断异常,这里捕获该异常并直接返回。 Copy for (int i = 0; i < somethings.size(); i++) { // 休眠 4 s try { Thread.sleep(4000); } catch (InterruptedException e) { // 抛出中断异常 return; } // 输出 System.out.println(somethings.get(i)); } 除了 InterruptedException 中断异常,另外还有三个中断相关的方法,三个方法都与线程相关。 thread#interrupt Thread#interrupted thread#isInterrupted interrupt 方法用于中断线程,但是并不是说该方法就能 直接使线程停止 。 下面使用 interrupt 中断线程,这里我们期望中断直接停止子线程输出。但是当主线程调用子线程 interrupt 方法,子线程并却没有被终止,还在继续打印数字。 Copy Runnable interruptedTask=new Runnable() { @Override public