死循环问题窥视系统main函数初始化之前操作
2016-04-09 00:01
441 查看
>
之前一个死锁问题,说也奇怪,代码没有修改,没有集成,没有crash,没有卡顿,突然发现有个功能无法用了。后来发现是子线程死循环了,导致功能的没有执行。从这个Bug,提了一个问题,在main函数之前,系统你在做什么?+load, 全局对象初始化,静态对象初始化,这些操作时序又是如何的呢?
+ _ attribute _((constructor))
+ +(void)load;
+ 全局变量初始化
+ 静态变量初始化
那他们的时序是: 这个时序很重要
load –> _ attribute _((constructor)) –> 全局变量初始化 –> 静态变量初始化
调用 load – 图片:
调用_ attribute _((constructor))– 图片:
调用全局变量初始化 图片:
调用静态变量初始化 图片:
下面是TMutex类的声明
原因说明:
在main函数执行之前:
1. 先调用了,+load函数
2. 再静态变量初始化,调用对象构造函数
由于在+load函数间接调用中,先调用了m_lock.create(), 此时函数调用时序错乱了(按道理应该先调用对象构造函数,在调用对象的方法函数,但是此时时序是相反的)
这样导致,先创建 pthread_mutex_t m_hMutex; // linux下需要此结构体对象成员变量,然后构造函数又把该成员变量清零。
最终导致,下一次调用该对象的lock方法时,发生死锁
对于每个技术细节,都要全面理解,之前我只知道main函数之前系统操作,但是没有深入挖掘了解时序信息,最后导致这个bug。所以深深感觉到『匠心长存』这几个字的含义,踏实做好各个环节。
之前一个死锁问题,说也奇怪,代码没有修改,没有集成,没有crash,没有卡顿,突然发现有个功能无法用了。后来发现是子线程死循环了,导致功能的没有执行。从这个Bug,提了一个问题,在main函数之前,系统你在做什么?+load, 全局对象初始化,静态对象初始化,这些操作时序又是如何的呢?
总结结论
对于XOS来说,系统main函数之前,会做大概如下四件事情+ _ attribute _((constructor))
+ +(void)load;
+ 全局变量初始化
+ 静态变量初始化
那他们的时序是: 这个时序很重要
load –> _ attribute _((constructor)) –> 全局变量初始化 –> 静态变量初始化
调用 load – 图片:
调用_ attribute _((constructor))– 图片:
调用全局变量初始化 图片:
调用静态变量初始化 图片:
描述死锁bug
简化死锁代码如下:@implementation FYAsserm + (void)load { //一个逻辑,触发好多个关联库,最后调到 DemoCPlusClass对象的m_lock.create() ,m_lock.lock() } @end class DemoCPlusClass { public: static TMutex m_lock; }; /** 构造函数 */ TMutex::TMutex() { memset(&m_hMutex, 0, sizeof(pthread_mutex_t)); } /** * 用指定的的名称创建一个新的互斥区 */ void TMutex::Create(bool isRecursive /*= V_TRUE*/) { size_t type = PTHREAD_MUTEX_NORMAL; if (isRecursive) { type = PTHREAD_MUTEX_RECURSIVE; } pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, (int)type); pthread_mutex_init((pthread_mutex_t*)&m_hMutex, &attr); } /** * 锁定TMutex对象 * @param uiWaiting [in] 等待时间(单位:毫秒) * * @return 成功返回true,否则返回false */ bool TMutex::Lock(size_t uiWaiting) { if(uiWaiting == T_INFINITY_WAIT) { while(pthread_mutex_trylock((pthread_mutex_t*)&m_hMutex) != 0) { TSleep(10); } return true; } else { size_t iWaiting = uiWaiting; while(pthread_mutex_trylock((pthread_mutex_t*)&m_hMutex) != 0) { iWaiting -= 10; if(iWaiting <= 0) return false; TSleep(10); } return true; } }
下面是TMutex类的声明
/* * 类名: TMutex * 功能: 互斥锁对象 */ class TMutex { public: /** 构造函数和析构函数 */ TMutex(); TMutex(TBool bInitLock); virtual ~TMutex(); public: /** * 用指定的的名称创建一个新的互斥区 */ void Create(bool isRecursive = true); /** * 锁定TMutex对象 * @param uiWaiting [in] 等待时间(单位:毫秒) * * @return 成功返回true, 否则返回false. */ bool Lock(size_t uiWaiting = T_INFINITY_WAIT); /** * 释放TMutex对象 * @return 成功返回true, 否则返回false. */ bool Unlock(); /** * 得到TMutex的句柄 * @return 事件的句柄 */ THandle GetHandle(); protected: bool m_bInit; pthread_mutex_t m_hMutex; // linux下需要此结构体 };
原因说明:
在main函数执行之前:
1. 先调用了,+load函数
2. 再静态变量初始化,调用对象构造函数
由于在+load函数间接调用中,先调用了m_lock.create(), 此时函数调用时序错乱了(按道理应该先调用对象构造函数,在调用对象的方法函数,但是此时时序是相反的)
这样导致,先创建 pthread_mutex_t m_hMutex; // linux下需要此结构体对象成员变量,然后构造函数又把该成员变量清零。
最终导致,下一次调用该对象的lock方法时,发生死锁
bool TMutex::Lock(size_t uiWaiting) { if(uiWaiting == T_INFINITY_WAIT) { while(pthread_mutex_trylock((pthread_mutex_t*)&m_hMutex) != 0) //死循环 -- 返回值为22,表示无效锁 { TSleep(10); } return true; }
对于每个技术细节,都要全面理解,之前我只知道main函数之前系统操作,但是没有深入挖掘了解时序信息,最后导致这个bug。所以深深感觉到『匠心长存』这几个字的含义,踏实做好各个环节。
相关文章推荐
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 峰回路转,Firefox 浏览器即将重返 iOS 平台
- 不可修补的 iOS 漏洞可能导致 iPhone 4s 到 iPhone X 永久越狱
- iOS 12.4 系统遭黑客破解,漏洞危及数百万用户
- 每日安全资讯:NSO,一家专业入侵 iPhone 的神秘公司
- [转][源代码]Comex公布JailbreakMe 3.0源代码
- 讲解iOS开发中基本的定位功能实现
- iOS中定位当前位置坐标及转换为火星坐标的方法
- js判断客户端是iOS还是Android等移动终端的方法
- iOS应用中UISearchDisplayController搜索效果的用法
- IOS开发环境windows化攻略
- iOS应用中UITableView左滑自定义选项及批量删除的实现
- 浅析iOS应用开发中线程间的通信与线程安全问题
- 检测iOS设备是否越狱的方法
- .net平台推送ios消息的实现方法
- 探讨Android与iOS,我们将何去何从?
- Android、iOS和Windows Phone中的推送技术详解
- iOS推送的那些事
- IOS 改变键盘颜色代码