死循环问题窥视系统main函数初始化之前操作

>
之前一个死锁问题,说也奇怪,代码没有修改,没有集成,没有crash,没有卡顿,突然发现有个功能无法用了。后来发现是子线程死循环了,导致功能的没有执行。从这个Bug,提了一个问题,在main函数之前,系统你在做什么?+load, 全局对象初始化,静态对象初始化,这些操作时序又是如何的呢?

总结结论

对于XOS来说,系统main函数之前,会做大概如下四件事情
+ _ attribute _((constructor))
+ +(void)load;
+ 全局变量初始化
+ 静态变量初始化

那他们的时序是: 这个时序很重要
load –> _ attribute _((constructor)) –> 全局变量初始化 –> 静态变量初始化

调用 load – 图片:
死循环问题窥视系统main函数初始化之前操作_第1张图片

调用_ attribute _((constructor))– 图片:
死循环问题窥视系统main函数初始化之前操作_第2张图片

调用全局变量初始化 图片:
死循环问题窥视系统main函数初始化之前操作_第3张图片

调用静态变量初始化 图片:
死循环问题窥视系统main函数初始化之前操作_第4张图片

描述死锁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。所以深深感觉到『匠心长存』这几个字的含义,踏实做好各个环节。

你可能感兴趣的:(ios)