ART学习笔记Thread SuspendAll部分

【FreeRtos教程七】STM32 CubeMx——EventGroup(事件组) 一个事件标志组有多个事件位,每个事件位表示了一个事件的标志。 比如我们用事件标志组的bit0表示事件A、bit1表示事件B、bit2表示事件C,那么这个事件标志组至少可以表示3个事件是否发生。 之前我们讲过信号量,它用作信号同步时,只能表示一个资源的有无;而事件标志组,它可以同时表示多个资源的有无。 阅读详情

昨天碰到了一个Gc 时Suspend  All 超时导致的Runtime abort问题。

顺带就研究了下Suspend的机制以及超时检查的机制。


第一部分,suspend机制:


在进程被signal 3或者GC或者debugger尝试attach,就会suspend,那么suspend是如何实现的呢?

首先看一个Thread的 dump

"android.fg" prio=5 tid=19 Native
  | group="" sCount=1 dsCount=0 obj=0x12e5b740 self=0xb482f000
  | sysTid=590 nice=0 cgrp=default sched=0/0 handle=0xb4926d80
  | state=S schedstat=( 0 0 0 ) utm=59 stm=63 core=0 HZ=100
  | stack=0xa39f2000-0xa39f4000 stackSize=1036KB
  | held mutexes=
  native: #00 pc 000133cc  /system/lib/libc.so (syscall+28)
  native: #01 pc 000a99eb  /system/lib/libart.so (art::ConditionVariable::Wait(art::Thread*)+82)
  native: #02 pc 0027c8a5  /system/lib/libart.so (art::GoToRunnable(art::Thread*)+756)
  native: #03 pc 00087679  /system/lib/libart.so (art::JniMethodEnd(unsigned int, art::Thread*)+8)
  native: #04 pc 000b39d5  /data/dalvik-cache/arm/system@framework@boot.oat (Java_android_os_MessageQueue_nativePollOnce__JI+112)
  at android.os.MessageQueue.nativePollOnce(Native method)
  at android.os.MessageQueue.next(MessageQueue.java:143)
  at android.os.Looper.loop(Looper.java:122)
  at android.os.HandlerThread.run(HandlerThread.java:61)
  at com.android.server.ServiceThread.run(ServiceThread.java:46)

这个线程在Jni方法调用返回,想从native状态切换为Runnable状态时,检测到当前线程的suspend flag在位,于是进入conditionwait等待唤醒。


ART线程通过TransitionFreomSuspendToRunnable以及TransitionFromRunnableToSuspended两个函数来完成Runable到suspend或其他状态的转换。

而线程的常见状态有如下多种:

enum ThreadState {
  //                                   Thread.State   JDWP state
  kTerminated = 66,                 // TERMINATED     TS_ZOMBIE    Thread.run has returned, but Thread* still around
  kRunnable,                        // RUNNABLE       TS_RUNNING   runnable
  kTimedWaiting,                    // TIMED_WAITING  TS_WAIT      in Object.wait() with a timeout
  kSleeping,                        // TIMED_WAITING  TS_SLEEPING  in Thread.sleep()
  kBlocked,                         // BLOCKED        TS_MONITOR   blocked on a monitor
  kWaiting,                         // WAITING        TS_WAIT      in Object.wait()
  kWaitingForGcToComplete,          // WAITING        TS_WAIT      blocked waiting for GC
  kWaitingForCheckPointsToRun,      // WAITING        TS_WAIT      GC waiting for checkpoints to run
  kWaitingPerformingGc,             // WAITING        TS_WAIT      performing GC
  kWaitingForDebuggerSend,          // WAITING        TS_WAIT      blocked waiting for events to be sent
  kWaitingForDebuggerToAttach,      // WAITING        TS_WAIT      blocked waiting for debugger to attach
  kWaitingInMainDebuggerLoop,       // WAITING        TS_WAIT      blocking/reading/processing debugger events
  kWaitingForDebuggerSuspension,    // WAITING        TS_WAIT      waiting for debugger suspend all
  kWaitingForJniOnLoad,             // WAITING        TS_WAIT      waiting for execution of dlopen and JNI on load code
  kWaitingForSignalCatcherOutput,   // WAITING        TS_WAIT      waiting for signal catcher IO to complete
  kWaitingInMainSignalCatcherLoop,  // WAITING        TS_WAIT      blocking/reading/processing signals
  kWaitingForDeoptimization,        // WAITING        TS_WAIT      waiting for deoptimization suspend all
  kWaitingForMethodTracingStart,    // WAITING        TS_WAIT      waiting for method tracing to start
  kStarting,                        // NEW            TS_WAIT      native thread started, not yet ready to run managed code
  kNative,                          // RUNNABLE       TS_RUNNING   running in a JNI native method
  kSuspended,                       // RUNNABLE       TS_RUNNING   suspended by GC or debugger
};

在线程切换Suspend状态时,首先是需要将suspendcount++,并将标志KSuspendRequest置位。

这样,在很多场景(几乎各个跳转场景,目前我还没弄清出解释器的执行方式)下在checkSuspend的时候,就会block住:

static inline void CheckSuspend(Thread* thread) {
  for (;;) {
    if (thread->ReadFlag(kCheckpointRequest)) {
      thread->RunCheckpointFunction();
    } else if (thread->ReadFlag(kSuspendRequest)) {
      thread->FullSuspendCheck();
    } else {
      break;
    }
  }
}

void Thread::FullSuspendCheck() {
  VLOG(threads) << this << " self-suspending";
  ATRACE_BEGIN("Full suspend check");
  // Make thread appear suspended to other threads, release mutator_lock_.
  TransitionFromRunnableToSuspended(kSuspended);
  // Transition back to runnable noting requests to suspend, re-acquire share on mutator_lock_.
  TransitionFromSuspendedToRunnable();
  ATRACE_END();
  VLOG(threads) << this << " self-reviving";
}


或者在JNI函数退出的时候,尝试从Native状态切成Runnable的时候,也会去做TransitionFreomSuspendToRunnable

在JNI函数进入的时候,从Runnalbe状态切到Native的时候,也会去做TransitionFromRunnableToSuspended

extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) {
  GoToRunnable(self);
  PopLocalReferences(saved_local_ref_cookie, self);
}


static void GoToRunnable(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
  mirror::ArtMethod* native_method = self->GetManagedStack()->GetTopQuickFrame()->AsMirrorPtr();
  bool is_fast = native_method->IsFastNative();
  if (!is_fast) {
    self->TransitionFromSuspendedToRunnable();
  } else if (UNLIKELY(self->TestAllFlags())) {
    // In fast JNI mode we never transitioned out of runnable. Perform a suspend check if there
    // is a flag raised.
    DCHECK(Locks::mutator_lock_->IsSharedHeld(self));
    CheckSuspend(self);
  }
}


那么下面就去看看这个函数的实现:

inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {
  AssertThreadSuspensionIsAllowable();
  DCHECK_NE(new_state, kRunnable);
  DCHECK_EQ(this, Thread::Current());
  // Change to non-runnable state, thereby appearing suspended to the system.
  DCHECK_EQ(GetState(), kRunnable);
  union StateAndFlags old_state_and_flags;
  union StateAndFlags new_state_and_flags;
  while (true) {
    old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
    if (UNLIKELY((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0)) {
      RunCheckpointFunction();
      continue;
    }
    // Change the state but keep the current flags (kCheckpointRequest is clear).
    DCHECK_EQ((old_state_and_flags.as_struct.flags & kCheckpointRequest), 0);
    new_state_and_flags.as_struct.flags = old_state_and_flags.as_struct.flags;
    new_state_and_flags.as_struct.state = new_state;

    // CAS the value without a memory ordering as that is given by the lock release below.
    bool done =
        tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakRelaxed(old_state_and_flags.as_int,
                                                                        new_state_and_flags.as_int);
    if (LIKELY(done)) {
      break;
    }
  }
  // Release share on mutator_lock_.
  Locks::mutator_lock_->SharedUnlock(this);
}
可以切换到suspend状态比较简单,置位+放锁mutator,这个放锁非常重要,是超时检测 机制的核心状态,后面会详细讲。

从suspend状态切回runnable:

inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
  bool done = false;
  union StateAndFlags old_state_and_flags;
  old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
  int16_t old_state = old_state_and_flags.as_struct.state;
  DCHECK_NE(static_cast<ThreadState>(old_state), kRunnable);
  do {
    Locks::mutator_lock_->AssertNotHeld(this);  // Otherwise we starve GC..
    old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
    DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
    if (UNLIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0)) {
      // Wait while our suspend count is non-zero.
      MutexLock mu(this, *Locks::thread_suspend_count_lock_);
      old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
      DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
      while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {// 当未被唤醒时,KsuspendRequst始终不为0,因此,进入conditionwait,也就是上面发的dump那样
        // Re-check when Thread::resume_cond_ is notified.
        Thread::resume_cond_->Wait(this);
        old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
        DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
      }
      DCHECK_EQ(GetSuspendCount(), 0);
    }
    // Re-acquire shared mutator_lock_ access.
    Locks::mutator_lock_->SharedLock(this);
    // Atomically change from suspended to runnable if no suspend request pending.
    old_state_and_flags.as_int = tls32_.state_and_flags.as_int;
    DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
    if (LIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) == 0)) {
      union StateAndFlags new_state_and_flags;
      new_state_and_flags.as_int = old_state_and_flags.as_int;
      new_state_and_flags.as_struct.state = kRunnable;
      // CAS the value without a memory ordering as that is given by the lock acquisition above.
      done =
          tls32_.state_and_flags.as_atomic_int.CompareExchangeWeakRelaxed(old_state_and_flags.as_int,
                                                                          new_state_and_flags.as_int);
    }
    if (UNLIKELY(!done)) {
      // Failed to transition to Runnable. Release shared mutator_lock_ access and try again.
      Locks::mutator_lock_->SharedUnlock(this);
    } else {
      return static_cast<ThreadState>(old_state);
    }
  } while (true);

首先去检测,当ksuspendrequst在位时,进入condition wait等待唤醒,唤醒完毕后,那mutator lock,并改变当前的状态,注意这里使用的是原子操作。

其实我们可以看到,suspend的核心就是在KsuspendRequset标志位在位的时候,线程会进入condition wait中等待唤醒,于是乎就suspend停了下来。

那么问题来了,如何检测所有的进程已经suspend好了以便我执行下面的操作了?


第二部分,suspend超时检测机制。

上面有提到,在进入suspend和runnalbe状态的时候,跟随着对mutatorlock的lock和unlock,mutatorlock是线程在运行的时候需要拿的锁,很多函数都声明了需要这个lock的保护,那么我们可以根据mutatorlock的状态来检测是否还有人处于runnalbe状态,art的实现如下:

  // Block on the mutator lock until all Runnable threads release their share of access.
#if HAVE_TIMED_RWLOCK
  // Timeout if we wait more than 30 seconds.
  if (!Locks::mutator_lock_->ExclusiveLockWithTimeout(self, 30 * 1000, 0)) {
    
        UnsafeLogFatalForThreadSuspendAllTimeout();
  }
#else
  Locks::mutator_lock_->ExclusiveLock(self);
#endif

尝试去获取mutator_lock,并设置了超时时间为30s,具体的实现就是一个futex_wait,这里就不说了。

其实在dumplog中我们只要找到状态为runnalbe的线程,就是导致超时的原因了。

顺带在说下为什么在synchronized中等待的(blocked)线程并不会超时:

synchronized的实现就就是Monitor,这个和dvm中的实现比较类似,都是基于thin和fat lock的。

当线程进入synchronized等待现在锁的持有者执行完毕的时候,会将自己的状态从runnable切换成block,同时创建了ScopedThreadStateChange对象,而对象的构造函数中调用了上面的方法:

class ScopedThreadStateChange {
 public:
  ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
      LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_) ALWAYS_INLINE
      : self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) {
    if (UNLIKELY(self_ == NULL)) {
      // Value chosen arbitrarily and won't be used in the destructor since thread_ == NULL.
      old_thread_state_ = kTerminated;
      Runtime* runtime = Runtime::Current();
      CHECK(runtime == NULL || !runtime->IsStarted() || runtime->IsShuttingDown(self_));
    } else {
      DCHECK_EQ(self, Thread::Current());
      // Read state without locks, ok as state is effectively thread local and we're not interested
      // in the suspend count (this will be handled in the runnable transitions).
      old_thread_state_ = self->GetState();
      if (old_thread_state_ != new_thread_state) {
        if (new_thread_state == kRunnable) {
          self_->TransitionFromSuspendedToRunnable();
        } else if (old_thread_state_ == kRunnable) {
          self_->TransitionFromRunnableToSuspended(new_thread_state);
        } else {
          // A suspended transition to another effectively suspended transition, ok to use Unsafe.
          self_->SetState(new_thread_state);
        }
      }
    }
  }

所以,被block住的线程,也是放掉了mutator_lock的。

在我现在看来,mutatorlock就是线程是否在可执行状态的标志。

总结下,suspend就是将KsuspendRequest置位,在线程执行的某些位置会进行检查,从而完成其他状态到suspend的切换,同时unlock mutatorlock。

suspend的检查就是尝试在30s内获取mutatorlock,如果超时,那么证明还有线程还没有执行完毕当前的任务,则dump stack,并runtime abort。

好了,就到这里,备忘备忘,不过肯定有理解错误的,我很担心我猜测的checksuspend执行点的错误,后面碰到问题再看。











【FreeRtos教程三】STM32 CubeMx——Message Queue(消息队列) 消息队列类似于数据结构中的“队列”,都是一个线性的存储表。可以往队列里面写入数据,也可从队列里面读取数据。 阅读详情

相关推荐

抗性基因分析避坑指南:从数据库选择到结果解读的全流程经验分享

本文系统分享了抗性基因分析从数据库选择到结果解读的全流程避坑经验。针对宏基因组研究,重点剖析了SARG、BacMet等核心数据库的适用场景与组合策略,并提供了实验设计、序列比对阈值设定、丰度归一化及结果生物学解读的关键优化建议,旨在帮助研究者获得更可靠、深入的分析结果。

weixin_29233333的博客 200

Android ART虚拟机系列: 虚拟机CheckPoint机制分析

线程运行时执行Check Point闭包任务;挂起和恢复线程的执行;虚拟机为了实现这两个功能,在Java线程对应的Native类中添加了变量,通过设置或者来通知线程需要执行挂起任务还是闭包任务。具体执行任务的时机是在函数中,这函数(检查点)被插入到了解释执行和机器码执行的多个流程中,这样,Runnable状态的线程就能快速执行到检查点,完成线程挂起或者执行闭包任务。如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。

m0_56255097的博客 1975

Win11右键菜单显示更多选项设置默认展开方法

在Windows 11操作系统中,用户可能会发现右键点击桌面空白处时,弹出的菜单中仅显示“显示更多选项”,而并非直接展示所有可用的选项。这对于希望快速访问特定功能的用户来说,无疑增加了一些不便。为了优化这一体验,本文将介绍两种简单的方法,帮助用户设置Win11右键菜单,使其默认展开包含的所有选项。通过上述两种方法,用户可以轻松地将Win11右键菜单设置为默认展开所有选项,从而提高工作效率和便捷性。希望这篇文章对你有所帮助!

nntxthml的博客 1万+

对IDEA中断点Suspend 属性理解

Suspend属性值分为all和thread

赵发财 3337

十一、Cadence ic 617以及assura使用总结

1.617的端口和514不同,没有网络属性,使用时不能直接放在原理图上,如果要直接放在图上要接线并且放上标签。2.617的端口也不能直接放在线上,514中将端口直接放在线上是可以使端口和线连接,但617看似连接,但拉出来线没有交点,实际上没有连接。这里set switches里的选项表示不同的模块,也就是选择一个就只对这一部分进行DRC验证,要验证整个版图的DRC就要把所有的选项选中,然后一个个改正。LVS中也是一样,要全部选中改正。

0 2295

vue3 - 详细实现用户收货地址识别解析“姓名/手机号/省市区/街道/乡镇村庄“关键字,用户复制粘贴一段含有姓名电话/详细地址的文字文本信息,vue3自动识别拆分并填入到对应表单字段中,详细示例代码

vue3,nuxt3,快递地址读取,收货地址解析、快递地址解析、物流地址解析自动识别,收货地址解析,从发货地址中拆出姓名电话地址,根据粘贴的字符串提取姓名地址,vue3地址信息自动识别,ts,vue3智能识别地址,提取姓名电话地址信息,自动识别出省市区街道姓名手机号等,根据文本自动解析出收货信息,怎么识别文本中的手机号,粘贴板地址识别,地址智能识别,如何识别收货地址中的关键字,粘贴一段文字后,自动识别到姓名/手机号/收货地址,vue3仿淘宝地址智能识别解析实现,省市区街道智能解析,vue3收货地址,识别地址

✅ 精选推荐文章 5501

Android 稳定性【篇二:ANR&SWT】

ANR(Application Not Responding,即应用程序无响应)。在Android中,当应用程序在规定时间内没有处理完毕相应的事件,系统就会报出ANR。

qq_27672101的博客 6432

YOLOv11来了,使用YOLOv11训练自己的数据集和推理(附YOLOv11网络结构图)

YOLOv11 由 Ultralytics 在 2024 年 9 月 30 日发布, 最新的 YOLOv11 模型在之前的 YOLO 版本引入了新功能和改进,以进一步提高性能和灵活性。YOLO11 在快速、准确且易于使用,使其成为各种对象检测和跟踪、实例分割、图像分类和姿态估计任务的绝佳选择。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 28万+

(转)ART学习笔记Thread SuspendAll部分

昨天碰到了一个Gc 时Suspend &nbsp;All 超时导致的Runtime abort问题。 顺带就研究了下Suspend的机制以及超时检查的机制。 第一部分,suspend机制: 在进程被signal 3或者GC或者debugger尝试attach,就会suspend,那么suspend是如何实现的呢? 首先看一...

深厚的积淀才有人生的升华 2290

C#串口通信从入门到精通(7)——整数/浮点数与二进制、八进制、十六进制之间的转换与C#实现

本文详细介绍由博主开发的DataConvert串口通信帮助类的用法,该帮助类涵盖了串口通信领域所有的数据转换方法,帮助大家快速编写串口通信程序!

qq_34059233的博客 2879

字节系,ali系,ks,pdd最新抓包方案

各大厂安卓逆向

qq_38759383的博客 1145

android tsclib.so,Android trace 文件抓取原理

By HuangTao of TinyLab.org2016-11-03 09:04:30Android 系统每次发生 ANR 后,都会在 /data/anr/ 目录下面输出一个 traces.txt 文件,这个文件记录了发生问题进程的虚拟机相关信息和线程的堆栈信息,通过这个文件我们就能分析出当前线程正在做什么操作,继而可以分析出 ANR 的原因,它的生成与 Signal Catcher 线程是息...

weixin_36190910的博客 366

用 ABAP CDS Table Function 把复杂计算下沉到 SAP HANA:从定义到 AMDP 实战与 Clean Core 落地

摘要 CDS table function 是 SAP S/4HANA 开发中的关键工具,它允许在 ABAP CDS 中调用由 HANA 原生执行的函数逻辑,并以表形式返回结果集。其核心价值在于:弥补 CDS 表达式不足,将复杂计算(如排序、分组、币种换算等)安全地推送到数据库层执行,同时保持 CDS 的可组合性。实现方式是通过 AMDP 框架,在 ABAP 类中编写 SQLScript 代码。使用时需注意参数设计应区分业务语义与过滤条件,并严格遵守 client-safe 原则以避免跨客户端数据泄露风险。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1003

从 Java 调用一个 Native 函数

Java 调用Native函数,实际就是 JNI 调用。 我们将关注 Java端如何把参数传递到 Native,Java调用Native函数时,额外的做了哪些事情。 在前面分析Native 调用Java 函数时,直接打断点,就能得到调用 backtrace,那是得益于 GDB 对 Native代码的调试支持, 可以根据包含 symbols的 so库,自动帮忙我们理清

大将军王虎剩的专栏 6090

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

ART运行时垃圾收集(GC)过程分析

ART运行时与Dalvik虚拟机一样,都使用了Mark-Sweep算法进行垃圾回收,因此它们的垃圾回收流程在总体上是一致的。但是ART运行时对堆的划分更加细致,因而在此基础上实现了更多样的回收策略。不同的策略有不同的回收力度,力度越大的回收策略,每次回收的内存就越多,并且它们都有各自的使用情景。这样就可以使得每次执行GC时,可以最大限度地减少应用程序停顿。本文就详细分析ART运行时的垃圾收集过程。

老罗的Android之旅 6万+

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

[FreeRTOS] 互斥量和互斥递归锁 Mutexes And Recursive Mutexes

1,谁获得,只能谁释放2,可以提高等待任务的优先级。

ooguaimua的博客 694

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

ART运行时之method/field加载

先简单介绍下OAT的文件格式,后面针对Method/Field/JNI方法加载做些代码分析。OAT文件格式 在虚拟机以ART模式运行的Android手机上,apk安装时,系统通过installed调用dex2oat将apk中的classes.dex优化成目标机器的本地机器指令,优化的oat文件放在/data/dalvik-cache目录下。 OAT文件是ELF格式文件,其包含2个重要的Secti

guoguodaern的专栏 4970

IDEA环境下的多线程调试方式

IDEA环境下的多线程调试方式 本文以最简陋的单例模式为例,示例如何使用IDEA调试多线程 1.代码准备 创建一个单例类 package com.lchtest.pattern.singleton.lazy; /** * 单例模式最基本条件 * 1.构造方法私有化 * 2.提供全局访问点 */ public class LazySimpleSingleton { publi...

weixin_41300437的博客 2384

定制ART跟踪JNI函数绑定

JNI函数的绑定:每一个JAVA层函数在native层都对应一个ArtMethod对象,JNI函数在执行前必须完成JNI函数所在类的加载和初始化、以及该JNI函数的ArtMethod对象当中属性和So中具体函数地址的绑定。 JNI函数绑定的分类: 1、静态: 两次绑定,第一次是在类加载的时候,会绑定到Art中的“桥函数”;第二次绑定是在该Jni函数第一次被真正调用时候,由Art完后该JNI函数在So中地址的查询以及绑定。 art_jni_dlsym_looup_stub_(汇编实现)->...

Viewz的博客 705

FreeRTOS实验_线程安全和中断安全printf方式

很多嵌入式开发人员都喜欢在开发过程中利用串口进行调试,这在裸机程序中无疑是很方便的。但是在搭载操作系统,使用多线程的情况下,几个线程同时打印数据甚至在打印过程中产生了中断并且中断程序中也要打印数据,这就难免发生数据交叉打印的现象。 下面就详细说明一下,如何解决这种问题。 首先,我们来看如何利用串口将printf数据显示到电脑的终端上。         由于printf最终是调用fpu

博客 9237

Linux命令c++filt

一个简单的linux命令, 确实不值得大费周折, 但是, 在实际的开发过程中,却帮助很大,在编译cgi,修改函数的调用之后获得函数的符号名,就可以看到这个函数的定义。 C/C++语言在编译以后,函数的名字会被编译器修改,改成编译器内部的名字,这个名字会在链接的时候用到。如果用backtrace之类的函数打印堆栈时,显示的就是被编译器修改过的名字,比如说_Z3foov 。 那么

a2796749的专栏 2281

STM32CubeMX学习笔记23---FreeRTOS(任务的挂起与恢复)

注:在不同任务(任务优先级相同)中同时使用同一个中断会导致任务轮流使用该中断,如LED1和LED2都延时1000ms后同时使用printf,则会出现以下情况,即两个任务轮流使用printf,就导致了中间的遗漏了。程序编译无误后下载到板子上,可以看到LED1计数到10时挂起LED2,当计数到15时恢复LED2。本实验通过freertos创建两个任务来分别控制LED2和LED3的亮灭,需要用到的硬件资源。在任务函数中编写程序,让LED1计数到10时挂起LED2,当计数到15时恢复LED2.

H2z1220的博客 1656

idea debug模式下的多线程切换

idea,dubug模式下切换线程,右键点击小红点,选择thread,然后使用F9键切换线程(suspend=all的时候是单个线程跑的,F8为下一步)。 另Condition:里面可以输入当前断点的条件 ...

天马行空的创作中心 2827

ANR backtrace含义

在thread_state.h中定义了线程状态,enum ThreadState { // Thread.State JDWP state kTerminated = 66, // TERMINATED TS_ZOMBIE Thread.run has returned,

xuwenwu1985的博客 1474

FastJNI导致的Android系统死机问题分析

1. 问题现象 问题发生的Android系统版本是7.0(Nougat); 滑动屏幕和按键都无响应,屏幕内容没有任何刷新; watchdog没有重启system_server; 问题现场可以连接adb; 2. 初步分析 对于死机问题,我们需要做一些分析前的准备工作: (1)拿到问题现场,及时充电以保证问题现场不被破坏; (2)如果没有现场可以忽略这一步,通过kill -3 后面...

宋金时的专栏 7892
上一篇: ART学习笔记 Rosalloc alloc部分
有梦想的胖子
博客等级 码龄16年 51粉丝 26原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值