Android native层的线程分析(C++),以及堆栈打印调试
文章目录
- Android native层的线程分析(C++),多线程实现
- 1.native线程的创建
- 第一部分:android_thread模块
- 第二部分:linux_thread模块
- 2.测试linux_thread模块
- 3.Android native的Thread类
- 3.1源码分析
- 4.native层堆栈调试方法
Android native层的线程分析(C++),多线程实现
1.native线程的创建
pthread_t //表示线程ID
pthread_equal (pthread_t __thread1, pthread_t __thread2);//比较线程ID
pthread_t pthread_self (void);//用户返回线程ID
pthread_create()//线程创建
编写Android.mk文件,
这个MK文件是一个Android.mk构建脚本,用于指导Android Native Development Kit (NDK)如何编译和链接两个可执行模块:android_thread
和 linux_thread
。下面是该脚本的详细解析:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)LOCAL_SRC_FILES := MyThread.cpp \Main.cpp \LOCAL_SHARED_LIBRARIES :=libandroid_runtime \libcutils \libutils \liblog LOCAL_MODULE := android_threadLOCAL_PRELINK_MODULE := falseinclude $(BUILD_EXECUTABLE)include $(CLEAR_VARS)LOCAL_SRC_FILES := thread_posix.c LOCAL_MODULE := linux_thread
LOCAL_SHARED_LIBRARIES :=liblog LOCAL_PRELINK_MODULE := falseinclude $(BUILD_EXECUTABLE)//把thread_posix.c 文件编译(BUILD_EXECUTABLE)成为一个二进制的可执行文件,这个二进制可执行文件的名字是linux_thread。
第一部分:android_thread模块
- LOCAL_PATH: 这一行定义了当前目录的路径,通过
my-dir
函数自动获取,作为查找其他文件(如源代码文件)的相对路径基础。 - include $(CLEAR_VARS): 这行代码包含了清除所有之前定义的LOCAL变量的脚本,确保为新模块提供一个干净的构建环境。
- LOCAL_SRC_FILES: 指定了要编译的源文件列表。在这个例子中,包括
MyThread.cpp
和Main.cpp
。 - LOCAL_SHARED_LIBRARIES: 列出了该模块需要链接的共享库,包括
libandroid_runtime
,libcutils
,libutils
, 和liblog
。这些都是Android系统提供的库,用于支持Android运行时功能、实用工具函数、日志输出等功能。 - LOCAL_MODULE: 定义了模块的名称,这里是
android_thread
。 - LOCAL_PRELINK_MODULE: 设定为
false
,表示该模块在预链接阶段不会被处理。预链接是一个可选步骤,通常用于减少应用启动时间,但在这里不适用。 - include $(BUILD_EXECUTABLE): 告诉NDK构建系统,根据前面定义的规则,将这些源文件编译成一个可执行文件。
第二部分:linux_thread模块
这部分结构与第一部分相似,但是针对另一个模块linux_thread
:
- LOCAL_SRC_FILES 只包含一个源文件:
thread_posix.c
,意味着这是一个基于POSIX线程标准实现的模块。 - LOCAL_SHARED_LIBRARIES 只列出了
liblog
,说明这个模块依赖于日志库来记录日志信息。 - 其他如
LOCAL_MODULE
、LOCAL_PRELINK_MODULE
以及最后的include $(BUILD_EXECUTABLE)
指令用法与android_thread
模块相同,用于构建名为linux_thread
的独立可执行模块。
综上所述,这个MK文件配置了两个C++/C语言编写的可执行模块的构建过程,一个是与Android系统紧密结合的android_thread
,另一个是使用POSIX线程API的linux_thread
,两者都将作为独立的可执行文件生成。
thread_posix.c
这段代码是一个简单的C语言程序,演示了如何在Linux或类Unix系统中使用POSIX线程库(pthread.h
)创建并管理一个线程。同时,它也使用了Android的日志系统(通过utils/Log.h
头文件)来记录日志信息。以下是代码的详细解释:
#include <pthread.h> // 包含POSIX线程库头文件
#include <stdlib.h> // 用于exit函数
#include <stdio.h> // 用于printf函数
#include <utils/Log.h> // 包含Android日志系统头文件// 定义线程执行的函数
void *thread_posix_function(void *arg) {(void*)arg; // 忽略传入的参数,这里没有使用int i;for (i = 0; i < 30; i++) {printf("hello thread i = %d\n", i); // 打印到标准输出ALOGD("hello thread i = %d\n", i); // 使用Android日志系统打印DEBUG级别日志sleep(1); // 线程暂停1秒}return NULL; // 线程函数结束,返回空指针
}int main(void) {pthread_t mythread; // 定义一个线程标识符// 创建一个新的线程,执行thread_posix_function函数,传入参数为NULLif (pthread_create(&mythread, NULL, thread_posix_function, NULL)) {ALOGD("error creating thread."); // 如果创建失败,记录错误日志abort(); // 终止程序执行}// 主线程等待mythread线程结束if (pthread_join(mythread, NULL)) {ALOGD("error joining thread."); // 如果等待失败,记录错误日志abort(); // 终止程序执行}ALOGD("hello thread has run end exit\n"); // 记录日志,表明线程已正确执行完毕exit(0); // 主程序正常退出
}
这段代码首先定义了一个线程执行的函数thread_posix_function
,该函数每隔一秒打印一次消息到控制台和Android日志系统,共打印30次。在main
函数中,它创建了一个新的线程并执行thread_posix_function
,然后主线程等待这个新线程完成其任务后才退出。整个过程中,还利用了Android的日志系统来报告错误或提供执行状态信息。
2.测试linux_thread模块
在安卓源码的根目录下创建一个文件夹,并写上mk文件,提供编译的脚本。
然后单独编译模块名即可 ===== LOCAL_MODULE
把编译后的可执行二进制文件push到设备中
执行一下,可以看到线程在打印输出。
3.Android native的Thread类
Android native的Thread类是Android提供的一个基础类
system\core\libutils\include\utils\Thread.h
system\core\libutils\Threads.cpp
智能指针,主要用来释放和控制内存。
virtual void onFirstRef();
第一次这个类被创建就会执行这个智能指针的这个方法,在这个方法里面我们就可以做一些事情了。执行线程创建并启动运行un方法,status_t run(const char* name, int32_t priority, size_t stack);,先执行readyToRun(),创建完成后,通过调用threadLoop()函数,线程请求退出方法,实现requestExit()函数。
3.1源码分析
run()方法,可以看到它也是用的pthread那套线程api,Android的native层的线程就是基于linux的pthread方案进行封装的。
进入_threadLoop
int Thread::_threadLoop(void* user)
{Thread* const self = static_cast<Thread*>(user);sp<Thread> strong(self->mHoldSelf);wp<Thread> weak(strong);self->mHoldSelf.clear();#if defined(__ANDROID__)// this is very useful for debugging with gdbself->mTid = gettid();
#endifbool first = true;do {bool result;if (first) {first = false;//我们一旦调用了线程的run方法之后首先执行的就是这个readyToRun方法。self->mStatus = self->readyToRun();result = (self->mStatus == OK);if (result && !self->exitPending()) {// Binder threads (and maybe others) rely on threadLoop// running at least once after a successful ::readyToRun()// (unless, of course, the thread has already been asked to exit// at that point).// This is because threads are essentially used like this:// (new ThreadSubclass())->run();// The caller therefore does not retain a strong reference to// the thread and the thread would simply disappear after the// successful ::readyToRun() call instead of entering the// threadLoop at least once.result = self->threadLoop();}} else {result = self->threadLoop();}// establish a scope for mLock{Mutex::Autolock _l(self->mLock);if (result == false || self->mExitPending) {self->mExitPending = true;self->mRunning = false;// clear thread ID so that requestExitAndWait() does not exit if// called by a new thread using the same thread ID as this one.self->mThread = thread_id_t(-1);// note that interested observers blocked in requestExitAndWait are// awoken by broadcast, but blocked on mLock until break exits scopeself->mThreadExitedCondition.broadcast();break;}}// Release our strong reference, to let a chance to the thread// to die a peaceful death.strong.clear();// And immediately, re-acquire a strong reference for the next loopstrong = weak.promote();} while(strong != nullptr);return 0;
}
测试
#ifndef _MYTHREAD_H
#define _MYTHREAD_H#include <utils/threads.h>namespace android {class MyThread: public Thread {
public:MyThread();virtual void onFirstRef();virtual status_t readyToRun();virtual bool threadLoop();virtual void requestExit();
private:int hasRunCount = 0;
};}
#endif
#define LOG_TAG "MyThread"#include <utils/Log.h>
#include "MyThread.h"namespace android {MyThread::MyThread() :Thread(false) {ALOGD("MyThread");}bool MyThread::threadLoop() {ALOGD("threadLoop hasRunCount = %d",hasRunCount);hasRunCount++;if (hasRunCount == 10) {return false; }return true;}void MyThread::onFirstRef() {ALOGD("onFirstRef");}status_t MyThread::readyToRun() {ALOGD("readyToRun");return 0;}void MyThread::requestExit() {ALOGD("requestExit");}
}
同上linux_thread操作编译push即可。
4.native层堆栈调试方法
android::CallStack()。所在线程的堆栈调用打印出来。
进入对应的cpp文件,解开注释,并且修改值为1
声明头文件
调用方法,
android::CallStack cs("zxx");cs.update();cs.log("zxx",ANDROID_LOG_ERROR,"=======================");
测试
相关文章:
Android native层的线程分析(C++),以及堆栈打印调试
文章目录 Android native层的线程分析(C),多线程实现1.native线程的创建第一部分:android_thread模块第二部分:linux_thread模块 2.测试linux_thread模块3.Android native的Thread类3.1源码分析 4.native层堆栈调试方法 Android native层的线…...
计算机科学:2024年高考生的明智之选?兴趣与趋势并重的决策指南
站在2024年这个时间节点上,计算机相关专业依然保持着其“万金油”地位,尽管面临一定的挑战,但其长期发展前景和就业潜力仍然乐观。以下是从不同身份角度出发的观点分析: 高考生视角: 如果你是今年的高考生࿰…...
跨界合作机会:通过淘宝数据挖掘潜在的合作伙伴与市场拓展方向
淘宝平台汇聚了众多商家和消费者,生成了大量的交易数据,这些数据为商家提供了挖掘跨界合作机会和市场拓展方向的丰富线索。以下是如何利用淘宝数据来寻找潜在的合作伙伴和探索新的市场机会的一些策略: 消费者行为分析:通过跟踪消费…...
如何利用智能家居打造一个“会呼吸的家”?一体化电动窗帘
如何利用智能家居打造一个“会呼吸的家”?一体化电动窗帘 史新华 隐藏式一体化智能电动窗帘与市面上其他窗帘不同的是,电机内置于轨道之中,一体化,美观、安静、滑动顺畅。 每次都会自动打开和关闭,相当漂亮。 众多家庭…...
PyTorch -- 最常见激活函数的选择
首先,简单复习下什么是梯度:梯度是偏微分的集合 举例说明:对于 z y 2 − x 2 : ∇ z ( ∂ z ∂ x , ∂ z ∂ y ) ( 2 x , 2 y ) z y^2-x^2: \nabla z (\frac{\partial z}{\partial x}, \frac{\partial z}{\partia…...
人工智能--制造业和农业
欢迎来到 Papicatch的博客 文章目录 🍉人工智能在制造业中的应用 🍈 应用场景及便利 🍍生产线自动化 🍍质量控制 🍍预测性维护 🍍供应链优化 🍈 技术实现及核心 🍍机器学习和…...
go语言,拼接字符串有哪些方式
目录 第一种方式: 使用加号"" 第二种方式: 使用fmt.Sprintf 第三种方式: 使用strings.Join 第四种方式: 使用strings.Builder 第五种方式: 使用bytes.Buffer go语言,拼接字符串的方式有…...
C++类型转换深度解析:从基础数据类型到字符串,再到基础数据类型的完美转换指南
前言 在 C 编程中,我们经常需要在基础数据类型(如 int、double、float、long、unsigned int 等)与 string 类型之间进行转换。这种转换对于处理用户输入、格式化输出、数据存储等场景至关重要。 本文将详细介绍如何在 C 中实现这些转换。 文…...
一文了解:渐进式web应用(PWA),原生应用还香吗?
前端开发是一个充满活力和不断演进的领域,各类技术层出不穷,PWA模式的出现就是想让web移动应用获得原生一样的体验,同时有大幅度降低开发成本,那么它到底能行吗?贝格前端工场带领大家了解一下。 一、什么是渐进式web应…...
SOLIDWORKS学生支持 可访问各种产品资源
你是不是一个热爱设计、追求创新的学生?你是不是在寻找一款能够帮助你实现设计梦想的工具?那么,SolidWorks学生支持是你的首要选择! SOLIDWORKS作为三维CAD设计软件,一直致力于为广大学生提供全方面的支持。无论你是初…...
VCS基本仿真
这里记录三种仿真方式: 第一种是将verilog文件一个一个敲在终端上进行仿真; 第二种是将多个verilog文件的文件路径整理在一个文件中,然后进行仿真; 第三种是利用makefile文件进行仿真; 以8位加法器为例: …...
Hbase中Rowkey的设计方法
Hbase中Rowkey的设计方法 过去对于Rowkey设计方法缺乏理解,最近结合多篇博主的文章,进行了学习。有不少心得体会。总结下来供后续学习和回顾。 一、设计Rowkey的三个原则 1.长度原则:长度不能太长,小于100个字节。可以偏端一些…...
Python基础总结之functools.wraps介绍与应用
Python基础总结之functools.wraps介绍与应用 在Python编程中,装饰器(decorator)是一种非常强大的工具,它允许开发者在不改变函数本身的情况下,动态地增加函数的功能。使用装饰器时,常常会用到 functools.wr…...
UE5基础1-下载安装
目录 一.下载 二.安装 三.安装引擎 四.其他 简介: UE5(Unreal Engine 5)是一款功能极其强大的游戏引擎。 它具有以下显著特点: 先进的图形技术:能够呈现出令人惊叹的逼真视觉效果,包括高逼真的光影、材…...
前端实现获取后端返回的文件流并下载
前端实现获取后端返回的文件流并下载 方法一:使用Axios实现文件流下载优点缺点 方法二:使用封装的Request工具实现文件流下载优点缺点 方法三:直接通过URL跳转下载优点缺点 结论 在前端开发中,有时需要从后端获取文件流࿰…...
Windows下对于Qt中带 / 的路径的处理
在Windows下,如果你想使用操作系统的分隔符显示用户的路径,请使用 toNativeSeparators()。 请看以下代码: void Player::on_playBtn_clicked() {if (this->m_url.isEmpty()) {openMedia();if (this->m_url.isEmpty())return;}qDebug(…...
[leetcode]swap-nodes-in-pairs
. - 力扣(LeetCode) class Solution { public:ListNode* swapPairs(ListNode* head) {ListNode* dummyHead new ListNode(0);dummyHead->next head;ListNode* temp dummyHead;while (temp->next ! nullptr && temp->next->next !…...
国思RDIF.vNext全新低代码快速开发框架平台6.1版本发布(支持vue2、vue3)
1、平台介绍 RDIF.vNext,全新低代码快速开发集成框架平台,给用户和开发者最佳的.Net框架平台方案,为企业快速构建跨平台、企业级的应用提供强大支持。 RDIF.vNext的前身是RDIFramework框架,RDIF(Rapid develop Integrate Framewor…...
中国地市分布图
原文链接https://mp.weixin.qq.com/s?__bizMzUyNzczMTI4Mg&mid2247693904&idx1&snb54884975272eaecb1d0564cafc128d3&chksmfa76a96dcd01207b939b8852a08eea9852eeffa8cc51a3af055dfca5c999e93301237e95901b&token1851596113&langzh_CN#rd...
HCIA11 网络安全之本地 AAA 配置实验
AAA 提供 Authentication(认证)、Authorization(授权)和 Accounting(计费)三种安全功能。 • 认证:验证用户是否可以获得网络访问权。 • 授权:授权用户可以使用哪些服务。 •…...
用Python处理Excel的资源
用Python处理Excel的资源 python-excel 读写Excel文件 openpyxl openpyx文档l 读写Excel2010文件(即xlsx) openpyxl示例: from openpyxl import Workbook wb Workbook()# 获取active worksheet ws wb.active# 给单元格赋值 ws[A1] 4…...
2024年中国移动游戏市场研究报告
来源:点点数据: 近期历史回顾: 面向水泥行业的5G虚拟专网技术要求(2024).pdf 2024年F5G-A绿色万兆全光园区白皮书.pdf 2024年全球废物管理展望报告.pdf 内容管理系统 2024-2025中国羊奶粉市场消费趋势洞察报告.pdf 20…...
JS-12-es6常用知识-async
目录 1. 定义与概述 2. 使用方法 3. 注意事项 4. 应用场景 5. 示例代码 6.总结 async 是 JavaScript(包括 TypeScript)中的一个关键字,用于声明一个函数为异步函数。async其实是一个promise的语法糖,以下是关于 async 的详细…...
使用winscp 通过中转机器(跳板机、堡垒机)密钥远程连接服务器,保姆级别教程
1.winscp下载地址 winscp下载 2.安装自己选择位置 3.连接服务器 到这里,基本就是没有壁垒机的就可直接连接,传递文件 4.配置中转服务器(壁垒机、跳板机) 选择高级选项 配置utf-8的编码格式 配置中转服务器(壁垒机、跳板机) 设置中专机的密码或者私钥 配置私钥...
力扣-1984. 学生分数的最小差值
文章目录 力扣题目工程代码C实现python实现 力扣题目 给你一个 下标从 0 开始 的整数数组 nums ,其中 nums[i] 表示第 i 名学生的分数。另给你一个整数 k 。 从数组中选出任意 k 名学生的分数,使这 k 个分数间 最高分 和 最低分 的 差值 达到 最小化 。…...
激动人心的LayerDiffusion终于可以在ComfyUI中使用了
一、什么是LayerDiffusion 随着Stable Diffusion等散射模型的蓬勃发展,人工智能图形生成进入了一个崭新的阶段。我们可以仅仅通过文字提示,就可以让AI模型为我们生成逼真的图像。但是,目前主流的AI生成模型大多只能生成普通的RGB图像,对生成具有透明通道的图片能力还非常有限。…...
【JVM】finalize() 方法的定义与作用
finalize() 方法的定义与作用 定义 finalize() 方法是 Java 中的一种特殊方法,定义在 java.lang.Object 类中。它在对象被垃圾回收之前由垃圾回收器调用,用于执行清理操作。 方法签名: protected void finalize() throws Throwable作用 …...
这10个前端库,帮我在工作中赢得了不少摸鱼时间!!
文章目录 前言1、dayjs2、 lodash3、 Quill4、 crypto-js5、 viewerjs6、 localforage7、 vconsole8、 uuid9、 copy-text-to-clipboard10、 classnames前言 通过高效的工具提高工作效率,从而有更多的时间来处理其他重要的任务,或者……摸鱼。没错!就是摸鱼。毕竟,提高效率…...
(2024最新)CentOS 7上在线安装MySQL 5.7
在CentOS 7上安装MySQL 5.7并配置允许远程连接,以下是详细步骤: 1. 添加MySQL官方存储库 首先,下载并添加MySQL的官方存储库。默认情况下,添加的存储库可能会包含最新的MySQL版本(如MySQL 8.0),…...
【C++高阶】C++继承学习手册:全面解析继承的各个方面
📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C “ 登神长阶 ” 🤡往期回顾🤡:模板进阶 🌹🌹期待您的关注 🌹🌹 继承 📖1. 继承的概念及定义…...
网站制作网站制作公司咨询热线/seo网站优化方案摘要
应用场合 ①上拉输入、下拉输入可以用来检测外部信号;例如,按键等; ②浮空输入模式,由于输入阻抗较大,一般把这种模式用于标准通信协议的I2C、USART的接收端; ③普通推挽输出模式一般应用在输出电平为0和3…...
网站建设就业前景/品牌策划是做什么的
前几天写了一个2048程序,是基于python3pygame实现的,对于初学python的同学来说应该是很好的练手项目,现在将源码分享给大家,添加了清晰的注释,相信大家能看的很明白运行效果如下:游戏结束后的效果如下&…...
电子商务网站订单功能/郑州做网站推广资讯
2019独角兽企业重金招聘Python工程师标准>>> EventBus 3.0采用注解处理,为了提高效率可在编译时通过注解处理器生成索引代码。 但是如果使用索引的话就不能混淆被Subscribe注解的方法。 为了能够提高效率使用索引并且混淆被Subscribe注解的方法可以使***…...
深圳网站建设 卓/seo推广是做什么
ARAnchor 可用于将对象放置在AR场景中的现实世界的位置和方向。 概述 要追踪实体或虚拟对象相对于相机的位置和方向,请创建锚点对象,并使用add(anchor:)方法将其添加到AR会话中。 当你在世界追踪会话中启用planeDetection时,ARKit还会自动添加…...
佛山购物网站建设/打开百度网站
一、算法设计题1.设二叉树bt采用二叉链表结构存储。试设计一个算法输出二叉树中所有非叶子结点,并求出非叶子结点的个数。【答案】intcount0;void algo2(BTNode *bt){if (bt){if(bt->lchild || bt->rchild){printf(bt->data);count;}algo2(bt->lchild)…...
学做蛋糕什么网站/东莞seo技术
#include using namespace std; int * test() { // 创建一个int变量 int a 1; // 返回该变量的地址 return &a; } int main() { // 声明一个指针 int * p 0; // 将这个指针指向一个局部变量(函数执行完之后,变量的…...