热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android开发之Thread类分析(转载)

转自:http:blog.csdn.netllping2011articledetails9706599       在我们Linux系统中创建线程函数为:pthread_crea

  转自:http://blog.csdn.net/llping2011/article/details/9706599

 

       在我们Linux系统中创建线程函数为:pthread_create(),在Android中我们为线程封装了一个类Thread,实际调用的还是pthread_create()
当我们想创建线程的时候,只需要继承于这个Thread类并实现虚函数thread_loop()即可。

 

    frameworks/base/include/utils/threads.h  
    class Thread : virtual public RefBase  
    {  
    public:  
        // 创建一个Thread对象,但是并不立即启动线程函数  
        Thread(bool canCallJava = true);  
        virtual ~Thread();  
        // 开始启动线程函数,调用的是threadLoop  
        virtual status_t run(const char*name = 0, int32_t prority = PRIORITY_DEFAULT,  
                    size_t stack = 0);  
        // 申请退出这个线程  
        virtual void requestExit();  
        virtual status_t readyToRun();  
        // 调用requestExit()等待直到这个线程退出  
            status_t requestExitAndWait();  
        // 等待直到线程退出,如果没有启动立即返回  
            status_t join();  
    protected:  
        // 如果调用了requestExit()返回true  
        bool exitPending() const;  
    private:  
        // 这是实际的线程函数,继承类必须实现它,  
        // 返回true的话再次调用,返回false的话就会退出  
        virtual bool threadLoop() = 0;  
        // 禁止赋值  
        Thread& operator = (const Thread&);  
        // 内部类,被run函数调用,实际调用threadLoop  
        static int _threadLoop(void* user);  
        const bool mCanCallJava;  
            thread_id_t mThread;    // thread_id_t 其实是 void*类型  
        mutable Mutex mLock;  
            Condition mThreadExitedCondition;  
            status_t mStatus;  
        // 注意:所以操作这两个变量的地方都需要上锁  
        volatile bool mExitPending;  
        volatile bool mRunning;  
            sp mHoldSelf;  
    };  

 

我们首先看下Thread类的构造函数:

 

    Thread::Thread(bool canCallJava)   
        :   mCanCallJava(canCallJava),  
            mThread(thread_id_t(-1)),  
            mLock("Thrad::mLock"),  
            mStatus(NO_ERROR),  
            mExitPending(false), mRunnig(false)  
    {}  

 

真正启动线程的函数:

    status_t Thread::run(const char*name, int32_t priority, size_t stack)  
    {  
        Mutex::Autolock _l(mLock);  
        if(mRunnig)  
            return INVALID_OPERATION;  
        mState = NO_ERROR;  
        mExitPending = false;  
        mThread = thread_id_t(-1);  
        mHoldSelf = this;   // 保存着当前对象的引用  
        mRunning = true;  
        if (mCanCallJava)   
            res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread);  
        else  
            res = androidCreateRawThreadEtc(_threadLoop, this, name,   
                    priority, stack, &mThread);  
        if(res == false) {  
            mStatus = UNKNOWN_ERROR;  
            mRunning = false;  
            mThread = thread_id_t(-1);  
            mHoldSelf.clear();  
            return UNKNOWN_ERROR;  
        }  
        return NO_ERROR;  
    }  
    这里有个判断mCanCallJava是个什么东西?接着往下看  
    inline bool createThreadEtc(thread_func_t entryFunction, void* userData,  
                const char* threadName = "android:unnamed_thread",  
                int32_t threadPriority = PRIORITY_DEFAULT,  
                size_t threadStackSize = 0,  
                thread_id_t *threadId = 0)  
    {  
        return androidCreateThreadEtc(entryFunction, userData, threadName, threadPriority,  
            threadStackSize, threadId) ? true : false;  
    }         
    int androidCreateThreadEtc(thread_func_t entryFunction,   
                void* userData,  
                const char* threadName,  
                int32_t threadPriority = PRIORITY_DEFAULT,  
                size_t threadStackSize = 0,  
                thread_id_t *threadId = 0)  
    {  
        return gCreateThreadFn(entryFunction, userData, threadName, threadPriority,  
            threadStackSize, threadId);  
    }  

我们看到最后调用的是gCreateThreadFn这个函数,而gCreateThreadFn是个全局的函数指针,
static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
这里默认给它赋值为 androidCreateRawThreadEtc,这跟前面调用的是一样的???

既然是函数指针肯定有给它赋值的地方:

    void androidSetCreateThreadFunc(android_create_thread_fn func)  
    {  
        gCreateThreadFn = func;  
    }  

那这个函数在什么地方调用的呢?又给它赋什么值了呢?
我们找到了再AndroidRuntime类里面启动虚拟机的地方:

    int androidRuntime::startReg(JNIEnv* env)  
    {  
        androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);  
        return 0;  
    }  

这样如果我们的mCanCallJava如果为true的话,调用的就是:

    int AndroidRuntime::javaCreateThreadEtc(android_thread_func_t entryFunction,  
                    void* userData,  
                    const char* threadName,  
                    int32_t threadPriority,  
                    suze_t threadStackSize,  
                    android_thread_id_t *threadId)  
    {  
        void** args = (void**)malloc(3*sizeof(void*));  
        args[0] = (void*)entryFunction;  
        args[1] = userData;  
        args[2] = (void*)strdup(threadName);  
        return androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args.  
            threadName, threadPriority, threadStackSize, threadId);  
    }  

最后调用的还是同一个创建线程的函数只是回调函数不一样,这里变成了AndroidRuntime::javaThreadShell

    int AndroidRuntime::javaCreateThreadEtc(void* args)  
    {  
        voir* start = ((void**)args)[0];  
        voir* userData = ((void**)args)[1];  
        voir* name = ((void**)args)[2];  
        free(args);  
        JNIEnv* env;  
          
        javaAttachThread(name, &env);  
        result = (*(android_thead_func_t)start)(userData);  
        javaDetachThread();  
          
        free(name);  
        return result;  
    }  

这里线程函数javaThreadShell里面还是调用前面我们的_threadLoop函数,只不过在调用之前,调用
了javaAttachThread()将线程attach到JNI环境中去了,这样线程函数就可以调用JNI函数,最后线程
函数退出之后再调用javaDetachThread()退出JNI环境。

现在进入线程函数_threadLoop(),这是一个static函数

    int Thread::_threadLoop(void* user)  
    {  
        Thread* const self = static_cast(user);  
        sp strong(self->mHoldSelf);  
        wp weak(strong);  
        self->mHoldSelf.clear();  
          
        bool first = true;  
          
        do {    // 进入一个循环,通过判断返回值和内部退出标志位决定是否退出线程  
            bool result;  
            if (fisr) {  
                first = false;  
                self->mStatus = self->readyToRun();  
                result = (self->mStatus == NO_ERROR);  
                if (result && !self->exitPendind()) {    // 检查是否退出  
                    result = self->threadLoop(); // 调用实际线程函数  
                }  
            } else {  
                result = self->threadLoop();  
            }  
              
            {  
                Mutex::Autolock _l(self->mLock);  
                if (result == false || self->mExitPending) {  
                    self->mExitPending = true;  
                    self-mRunning = false;  
                    self->mThread = thread_ir_t(-1);  
                    self->mThreadExitedCondition.broadcast();  
                    break;  
                }  
              
            }  
            strong.clear();  
            strong = weak.promote();  
        } while(strong != 0);  
        return 0;  
    }  

在这里线程退出的条件为:
1)result = true 意味着子类在实现的threadLoop函数中返回false,这样线程就主动退出了
2)mExidPendding = true 这个变量值由Thread类的requestExit函数设置,这样线程就被动退出了。
最后如果线程退出了需要进行些去初始化操作,设置线程运行状态,广播告知其他关心这个线程的对象。

最后,如果我们想使用线程类:  
1)创建一个类如MyThread,继承与Thead类  
2)在MyThread类中实现父类的纯虚函数threadLoop,也就是我们调用pthread_create时传入的线程函数。  
3)定义一个MyThread变量 thread,调用线程的run()方法,启动函数 

 


推荐阅读
  • Linux线程的同步和互斥
    目录1、线程的互斥2、可重入VS线程安全3、线程的同步1、线程的互斥 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • UNIX高级环境编程 第11、12章 线程及其属性
    第11章线程11.2线程概念线程资源:线程ID,一组寄存器,栈,调度优先级和策略,信号屏蔽字,e ... [详细]
  • pthread_mutex_lockpthread_mutex_lock(pthread_mutex_t*mutex);intpthread_mutex_trylock(pthre ... [详细]
  • C语言编程gcc怎么生成静态库.a和动态库.so
    这篇文章将为大家详细讲解有关C语言编程gcc怎么生成静态库.a和动态库.so,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 第七课主要内容:多进程多线程FIFO,LIFO,优先队列线程局部变量进程与线程的选择线程池异步IO概念及twisted案例股票数据抓取 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了一个线程多次调用一个函数相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 不知道你是否还记得之前在进程中的信号处理时,提到过阻塞信号集与未决信号集的概念,如果你已经忘记了,请参考《阻塞信号与未决信号》一文回忆一下 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 基于分布式锁的防止重复请求解决方案
    一、前言关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查 ... [详细]
author-avatar
linxiuying261
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有