Android native层的线程分析(C++),以及堆栈打印调试

news2024/11/26 18:42:57

文章目录

  • 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_threadlinux_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_thread


LOCAL_PRELINK_MODULE := false

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := thread_posix.c 
	
LOCAL_MODULE := linux_thread
LOCAL_SHARED_LIBRARIES :=liblog  
	
LOCAL_PRELINK_MODULE := false

include $(BUILD_EXECUTABLE)

//把thread_posix.c 文件编译(BUILD_EXECUTABLE)成为一个二进制的可执行文件,这个二进制可执行文件的名字是linux_thread。

第一部分:android_thread模块

  1. LOCAL_PATH: 这一行定义了当前目录的路径,通过my-dir函数自动获取,作为查找其他文件(如源代码文件)的相对路径基础。
  2. include $(CLEAR_VARS): 这行代码包含了清除所有之前定义的LOCAL变量的脚本,确保为新模块提供一个干净的构建环境。
  3. LOCAL_SRC_FILES: 指定了要编译的源文件列表。在这个例子中,包括MyThread.cppMain.cpp
  4. LOCAL_SHARED_LIBRARIES: 列出了该模块需要链接的共享库,包括libandroid_runtime, libcutils, libutils, 和 liblog。这些都是Android系统提供的库,用于支持Android运行时功能、实用工具函数、日志输出等功能。
  5. LOCAL_MODULE: 定义了模块的名称,这里是android_thread
  6. LOCAL_PRELINK_MODULE: 设定为false,表示该模块在预链接阶段不会被处理。预链接是一个可选步骤,通常用于减少应用启动时间,但在这里不适用。
  7. include $(BUILD_EXECUTABLE): 告诉NDK构建系统,根据前面定义的规则,将这些源文件编译成一个可执行文件。

第二部分:linux_thread模块

这部分结构与第一部分相似,但是针对另一个模块linux_thread

  • LOCAL_SRC_FILES 只包含一个源文件:thread_posix.c,意味着这是一个基于POSIX线程标准实现的模块。
  • LOCAL_SHARED_LIBRARIES 只列出了liblog,说明这个模块依赖于日志库来记录日志信息。
  • 其他如LOCAL_MODULELOCAL_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函数,传入参数为NULL
    if (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 gdb
    self->mTid = gettid();
#endif

    bool 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 scope
            self->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 loop
        strong = 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,"=======================");

测试

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1816611.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[13] CUDA_Opencv联合编译过程

CUDA_Opencv联合编译过程 详细编译过程可见我之前的文章&#xff1a;Win10下OpencvCUDA联合编译详细教程&#xff08;版本455、460、470,亲测可用&#xff01;&#xff01;&#xff01;&#xff09;本文给出Windows\linux下的opencvcuda的编译总结&#xff0c;摘自 <基于GP…

【SSM】医疗健康平台-项目开发准备

知识目标 了解架构&#xff0c;能够说出常用的架构及其优缺点 熟悉项目的技术栈&#xff0c;能够说出每个技术栈的用途 了解项目的功能结构&#xff0c;能够说出医疗健康项目的功能组成 掌握医疗健康项目的环境搭建&#xff0c;能够根据系统模块的划分搭建医疗健康项目中的父…

Java基础面试重点-2

21. JVM是如何处理异常&#xff08;大概流程&#xff09;&#xff1f; 如果发生异常&#xff0c;方法会创建一个异常对象&#xff08;包括&#xff1a;异常名称、异常描述以及异常发生时应用程序的状态&#xff09;&#xff0c;并转交给JVM。创建异常对象&#xff0c;并转交给…

推荐系统三十六式学习笔记:原理篇.近邻推荐09|协同过滤中的相似度计算方法有哪些?

目录 相似度的本质相似度的计算方法&#xff1a;1、欧式距离2、余弦相似度3、皮尔逊相关度4 、杰卡德&#xff08;Jaccard&#xff09;相似度 总结 相似度的本质 推荐系统中&#xff0c;推荐算法分为两个门派&#xff0c;一个是机器学习派&#xff0c;一个是相似度门派。机器学…

pytorch版本与torchvision版本不匹配问题处理

pytorch版本与torchvision版本不匹配问题处理 问题问题复现解决方法两点注意内容其一&#xff1a;pytorch版本与torchvision版本对应关系其二&#xff1a;CPU版本或GPU版本问题 问题 在新环境中&#xff0c;利用yolov8训练模型的时候报错&#xff0c;错误内容如下&#xff1a;…

探囊取物之渐变背景登录页面(基于ElementUI)

低配置云服务器&#xff0c;首次加载速度较慢&#xff0c;请耐心等候 预览页面&#xff1a;http://www.daelui.com/#/tigerlair/saas/preview/lxbupnc9dg5q 演练页面&#xff1a;http://www.daelui.com/#/tigerlair/saas/practice/lxbupnc9dg5q

ansible-Role角色批量按照node_export节点,并追加信息到Prometheus文件中

文章目录 剧本功能 inventory.yaml文件定义deploy.yaml角色定义node_exporter_lock角色定义任务角色main.yamlnode_exporter_tasks.yml角色触发任务notifyextra_tasks.yml角色prometheus_node_config.j2模板文件 执行命令查看变量 剧本功能 功能1&#xff1a; 批量执行node_ex…

【电子通识】焊接常见的不良有哪些?

在焊接完成后的调试阶段&#xff0c;有时总会发生一些奇怪的异常。也许是因为在焊接过程中出现了一些莫名其妙的焊接缺陷&#xff0c; 这些焊接缺陷产生的原因各不相同。 在实际的SMT贴片加工或插件焊接中&#xff0c;我们一般会采取一些方法来避免这些焊接不良的现象。那么常见…

PyCharm2018图文安装教程、附录软件下载

软件简介 PyCharm 2018是一款IDE集成开发环境&#xff0c;主要功能包括代码调试、语法高亮、智能提示、单元测试、版本控制等&#xff0c;支持Python 3.7&#xff0c;改进search everywhere功能等&#xff0c;可以让用户快速的开发程序。 软件下载 复制链接浏览器打开 https…

HTML静态网页成品作业(HTML+CSS)—— 电影泰坦尼克号介绍网页(4个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有4个页面。 二、作品演示 三、代…

译译交友项目介绍

一、 项目背景 随着社会的进步&#xff0c;英语作为一种国际语言&#xff0c;很多人都在学习英语&#xff0c;然而现在很多人都会因为学习英语而烦恼&#xff0c;有时还会因为是一个人学习而感到枯燥。面对情绪的低落&#xff0c;往往会使学习更困难。因此&#xff0c;我打造了…

Protected and unprotected Meilisearch projects(/health)

Elasticsearch 做为老牌搜索引擎&#xff0c;功能基本满足&#xff0c;但复杂&#xff0c;重量级&#xff0c;适合大数据量。 MeiliSearch 设计目标针对数据在 500GB 左右的搜索需求&#xff0c;极快&#xff0c;单文件&#xff0c;超轻量。 所以&#xff0c;对于中小型项目来说…

Qt 实战(4)信号与槽 | 4.1、信号与槽机制

文章目录 一、信号与槽机制1、基本概念2、信号与槽函数连接2.1、connect宏实现信号与槽连接2.2、Qt5新connect函数2.3、使用函数指针2.4、使用lambda表达式2.5、使用Qt Creator添加信号的槽函数 3、结论 前言&#xff1a; Qt信号与槽机制是一种用于处理对象间通信的强大机制&am…

2003远程桌面端口修改,Windows Server 2003远程桌面端口修改的专业操作指南

在网络安全日益受到重视的今天&#xff0c;修改Windows Server 2003远程桌面的默认端口已成为提高服务器安全性的常规操作。默认情况下&#xff0c;远程桌面使用的端口为3389&#xff0c;这一广为人知的端口号常常成为黑客攻击的目标。因此&#xff0c;通过修改远程桌面端口&am…

代码随想录-二叉树 | 111 二叉树的最小深度

代码随想录-二叉树 | 111 二叉树的最小深度 LeetCode 111 二叉树的最小深度解题思路代码难点总结 LeetCode 111 二叉树的最小深度 题目链接 代码随想录 题目描述 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说…

地推数据不再迷茫,Xinstall助你一臂之力!

在移动互联网时代&#xff0c;地推作为一种传统的推广方式&#xff0c;仍然占据着举足轻重的地位。然而&#xff0c;地推过程中产生的数据却常常让推广者感到头疼。数据分散、难以追踪、分析困难……这些问题不仅耗费了推广者大量的时间和精力&#xff0c;更可能导致决策失误&a…

vue30:v-model语法糖的本质

在Vue.js框架中&#xff0c;v-model 是一个指令&#xff0c;用于在表单输入和应用状态之间创建双向数据绑定。它本质上是语法糖&#xff0c;意味着它提供了一种更简洁的方式来编写代码&#xff0c;而不需要显式地编写额外的代码。 具体来说&#xff0c;v-model 背后实际上是由…

LeetCode | 20.有效的括号

这道题就是栈这种数据结构的应用&#xff0c;当我们遇到左括号的时候&#xff0c;比如{,(,[&#xff0c;就压栈&#xff0c;当遇到右括号的时候&#xff0c;比如},),]&#xff0c;就把栈顶元素弹出&#xff0c;如果不匹配&#xff0c;则返回False&#xff0c;当遍历完所有元素后…

技术要转管理吗?PMP证书有用吗?

作为一名80后的IT项目经理&#xff0c;我从大学计算机专业毕业后就一直在.NET开发领域工作&#xff0c;直到获得PMP证书后转型成为项目经理。我的经历或许能为还在犹豫是否要从技术转型到管理岗位的学弟学妹们提供一些参考。 大多数人认为&#xff0c;计算机专业的大学毕业生通…

8.11 矢量图层线要素单一符号使用七(爆炸线)

文章目录 前言爆炸线&#xff08;Lineburst&#xff09;QGis设置线符号为爆炸线&#xff08;Lineburst&#xff09;二次开发代码实现爆炸线&#xff08;Lineburst&#xff09; 总结 前言 本章介绍矢量图层线要素单一符号中爆炸线&#xff08;Lineburst&#xff09;的使用说明&…