Android Thread使用注意事项

通过继承android::Thread,可以轻松定义一个自己想要的线程。
例如:
class MyThread : public android::Thread
{
public:
virtual bool threadLoop(); //重写threadLoop方法
};
问题关键我应该怎么实例化呢?
1、栈上定义,MyThread instance();
2、堆上定义,MyThread* instance = new MyThread();
3、使用android::sp堆上定义,android::sp instance = new MyThread();
一开始我是按照1来实例化的,运行的时候都是正常的,当退出线程的出现问题了
requestExit();//异步退出线程
join();//等待线程结束
发现join无法退出!!!
我们正式启动源码分析,来看这个问题的来龙去脉。android 源码在线阅读网址:http://androidxref.com/
1、从现象到log
现象上比较直接,所在应用直接卡死。初步在怀疑地方前后打log确认,但这个方法还是太low
快捷的方法使用ps指令获取进程号,debuggerd pid生成tombstones,目录/daa/tombstones,
分析tombstones的log,可以看到各个线程的状态,问题线程的backtrace,然后结合android::Thread的源码:
Thread类在O版本中路径在/system/core/libutils
805
806status_t Thread::join()
807{
808 Mutex::Autolock _l(mLock);
809 if (mThread == getThreadId()) {
810 ALOGW(
811 "Thread (this=%p): don’t call join() from this "
812 “Thread object’s thread. It’s a guaranteed deadlock!”,
813 this);
814
815 return WOULD_BLOCK;
816 }
817
818 while (mRunning == true) {
819 mThreadExitedCondition.wait(mLock); //线程等待在这里
820 }
821
822 return mStatus;
在requestExit的时候已经将退出变量mExitPending = true;理论上Thread::threaLoop(),会执行一遍之后,
self->mThreadExitedCondition.broadcast();然后退出do-while循环,join0()收到信号量之后,继续执行完。

再怎么分析下去呢,第一个想法是在Thread.cpp里加log,编译出libutils.so替换使用,但是将libutils.so 推到system/lib64之后发现log没有打印,在继续看下tomtstons调用libutils.so的路径不是/system/lib64路径下,而是system/lib64/vnd-sp路径下,替换之后Log打印出来了。

通过不断增加log之后,重大发现是join之前MyThread已经析构掉了,这是什么原因!!!
这得从Thread的定义说起
class Thread : virtual public RefBase
{}
Thread继承RefBase,所以Thread可以通过sp来管理生命周期
在看int Thread::_threadLoop(void* user)定义
int Thread::_threadLoop(void* user)
{
sp strong(self->mHoldSelf);
}
可以看到threadloop的实现里有使用sp智能指针,
已知SomeClass继承RefBase,如下,当退出{},sC会被delete,
SomeClass* sC = new SomeClass();//没有使用sp,sC内部的引用计数为0
{
sp spS = sC;//这个赋值操作会将sC的引用计数+1,从而变成1;当退出{}时,引用计数减1,从而引用计数变成0,触发析构
}

经过上面的分析,我们找到为什么Thread被析构的原因了。
通过上面的实验可以看出,如果一个类继承RefBase,那它就告诉调用者它支持引用计数,支持sp,同时也告诉调用者在创建实例时应该使用sp,否则就会出现提前释放的问题。

一旦一个类继承RefBase,那它必须从创建开始就必须使用sp(wp)来管理,详见RefBase.h
Any object inheriting from RefBase should always be destroyed as the result
128// of a reference count decrement, not via any other means. Such objects
129// should never be stack allocated, or appear directly as data members in other
130// objects. Objects inheriting from RefBase should have their strong reference
131// count incremented as soon as possible after construction. Usually this
132// will be done via construction of an sp<> to the object, but may instead
133// involve other means of calling RefBase::incStrong().
134// Explicitly deleting or otherwise destroying a RefBase object with outstanding
135// wp<> or sp<> pointers to it will result in an abort or heap corruption.

It is particularly important not to mix sp<> and direct storage management
138// since the sp from raw pointer constructor is implicit. Thus if a RefBase-
139// -derived object of type T is managed without ever incrementing its strong
140// count, and accidentally passed to f(sp), a strong pointer to the object
141// will be temporarily constructed and destroyed, prematurely deallocating the
142// object, and resulting in heap corruption. None of this would be easily
143// visible in the source.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值