Chinaunix首页 | 论坛 | 博客
  • 博客访问: 69520
  • 博文数量: 14
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 125
  • 用 户 组: 普通用户
  • 注册时间: 2020-05-25 15:21
文章分类

全部博文(14)

文章存档

2020年(14)

我的朋友

分类:

2020-05-26 13:30:30

浅析μCOS/II v2.85内核OSFlagPend()和OSFlagPost()函数工作原理

文章来源:http://gliethttp.cublog.cn[转载请声明出处]

//对于flag--"事件组"的使用,可以用一个简单的例子做说明:
// 比如,我现在用迅雷下载一部10集的连续剧,我打算10集全部下载完成之后,
//才开始正式看,现在3~10集因为种子原因,先早下完了,现在第1集下到了82%,
//第2集下到了97%,因为我的计划是10集全部下完才开始看,而第1集和第2集
//由于网络,种子等等各种原因,迟迟不能下载完成,进而导致我的计划被悬停,不能进行,
//已下载的8集,也因为前2集没能下完,而白白等待---这就等同于flag事件组,
//1~10集,每一集都是一个事件,因为我内定,10个事件全部完成之后,才进入下一事件--"观看"
//所以及早完成自己事件的第3~10集,将主动把自己通过flag事件组函数OSFlagPost()登记到事件组上,
//他们不关心,其他友邻事件完成否,只专注自己的事件是否完成,自己的事件一旦完成
//就登记到事件组上,最后3~10集,都把自己登记上去了,只剩下第1集和第2集,
//一旦某天的某个时刻,第2集下完了,那么第2集也把自己登记到事件组上,这样整个事件距离完成
//还剩下一个事件,就是第1集是否下载完成,只要第1集下载完成,那么我内定的"观看"计划
//开始启动,过了3分钟,由于网速提高,竟以300k的速度开始下载第1集,1分钟之后,
//第1集也下载完成了,第1集立即调用OSFlagPost事件组函数,将自己登记到事件组上,
//ok,OSFlagPost()检测到所有事件已经完成,OSFlagPost()将是"我"自动进入下一事件---"观看"
// 还有一点就是关于flag事件组和Sem,Mbox,Queue的区别之处,flag事件组不使用事件控制矩阵来
//管理被阻塞在事件上的task进程,flag事件组使用pgrp的双向链表来挂接起所有task,
//在OSFlagPost()中将遍历这个链表,查找符合当前flag事件的task,将该task从双向链表中摘下
//然后放入就绪控制矩阵中,之所以这样,是因为flag事件组不像Sem,Mbox,Queue那样具有二值性,
//即Sem,Mbox,Queue,要么有,要么没有,flag事件组,还要进一步判断,有的话,是什么程度的有.
//----------------------------------------------------------------------
//1.OSFlagPend()函数
OS_FLAGS OSFlagPend(OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U wait_type, INT16U timeout, INT8U *perr)
{
    OS_FLAG_NODE node;
    OS_FLAGS flags_rdy;
    INT8U result;
    INT8U pend_stat;
    BOOLEAN consume;
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR cpu_sr = 0;
#endif

#if OS_ARG_CHK_EN > 0
    if (perr == (INT8U *)0) {
        return ((OS_FLAGS)0);
    }
    if (pgrp == (OS_FLAG_GRP *)0) {
        *perr = OS_ERR_FLAG_INVALID_PGRP;
        return ((OS_FLAGS)0);
    }
#endif
    if (OSIntNesting > 0) {
//ISR中,不能使用OSFlagPend()
        *perr = OS_ERR_PEND_ISR;
        return ((OS_FLAGS)0);
    }
    if (OSLockNesting > 0) {
//μCOS/II v2.85内核已经被强制锁住
        *perr = OS_ERR_PEND_LOCKED;
        return ((OS_FLAGS)0);
    }
    if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) {
//确保该event控制块是flag类型
        *perr = OS_ERR_EVENT_TYPE;
        return ((OS_FLAGS)0);
    }
    result = (INT8U)(wait_type & OS_FLAG_CONSUME);
    if (result != (INT8U)0) {
//收到指定事件们之后,复位flag事件组,将相应的事件标志清0
        wait_type &= ~(INT8U)OS_FLAG_CONSUME;
        consume = OS_TRUE;
    } else {
        consume = OS_FALSE;
    }
    OS_ENTER_CRITICAL();
    switch (wait_type) {
        case OS_FLAG_WAIT_SET_ALL:
            //2007-09-09 gliethttp
            //flag事件组中所有事件都置位才唤醒
             flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & flags);
             if (flags_rdy == flags) {
            //flag事件组中指定的所有事件都已经登记了
                 if (consume == OS_TRUE) {
            //清除flag事件组中的相应事件标志位
                     pgrp->OSFlagFlags &= ~flags_rdy;
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;//返回成功的flag事件组值
                 OS_EXIT_CRITICAL();
                 *perr = OS_ERR_NONE;
                 return (flags_rdy);
             } else {
//flag事件组中指定的所有事件中,可能有1个还没有完成登记工作,所以本task悬停在flag事件控制矩阵中
            //2007-09-09 gliethttp
            //node为该task在栈空间上分配的数据,因为本task任务需要悬停,所以
            //位于该task栈空间上的node,不会被破坏,它和全局变量性质等同
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
        case OS_FLAG_WAIT_SET_ANY:
            //2007-09-09 gliethttp
            //flag事件组中指定的事件们,只要有一个事件发生置位就唤醒
             flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & flags);
             if (flags_rdy != (OS_FLAGS)0) {
                 if (consume == OS_TRUE) {
            //清除flag事件组中的相应事件标志位
                     pgrp->OSFlagFlags &= ~flags_rdy;
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;//返回成功的flag事件组值
                 OS_EXIT_CRITICAL();
                 *perr = OS_ERR_NONE;
                 return (flags_rdy);
             } else {
//flag事件组中指定的所有事件中,没有1个进行登记,所以悬停本task在flag事件控制矩阵中
            //2007-09-09 gliethttp
            //node为该task在栈空间上分配的数据,因为本task任务需要悬停,所以
            //位于该task栈空间上的node,不会被破坏,它和全局变量性质等同
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
#if OS_FLAG_WAIT_CLR_EN > 0
        case OS_FLAG_WAIT_CLR_ALL:
            //2007-09-09 gliethttp
            //flag事件组中所有事件都清0才唤醒
             flags_rdy = (OS_FLAGS)(~pgrp->OSFlagFlags & flags);
             if (flags_rdy == flags) {
            //flag事件组中指定的所有事件都已经把事件自己对应的位清0
                 if (consume == OS_TRUE) {
            //还原flag事件组中的相应事件标志位
                     pgrp->OSFlagFlags |= flags_rdy;
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;//返回成功的flag事件组值
                 OS_EXIT_CRITICAL();
                 *perr = OS_ERR_NONE;
                 return (flags_rdy);
             } else {
//flag事件组中指定的所有事件中,可能有1个还没有完成清0工作,所以本task悬停在flag事件控制矩阵中
            //2007-09-09 gliethttp
            //node为该task在栈空间上分配的数据,因为本task任务需要悬停,所以
            //位于该task栈空间上的node,不会被破坏,它和全局变量性质等同
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
        case OS_FLAG_WAIT_CLR_ANY:
            //2007-09-09 gliethttp
            //flag事件组中指定的事件们,只要有一个事件发生清0就唤醒
             flags_rdy = (OS_FLAGS)(~pgrp->OSFlagFlags & flags);
             if (flags_rdy != (OS_FLAGS)0) {
                 if (consume == OS_TRUE) {
            //还原flag事件组中的相应事件标志位
                     pgrp->OSFlagFlags |= flags_rdy;
                 }
                 OSTCBCur->OSTCBFlagsRdy = flags_rdy;//返回成功的flag事件组值
                 OS_EXIT_CRITICAL();
                 *perr = OS_ERR_NONE;
                 return (flags_rdy);
             } else {
//flag事件组中指定的所有事件中,没有1个发生清0操作,所以悬停本task在flag事件控制矩阵中
            //2007-09-09 gliethttp
            //node为该task在栈空间上分配的数据,因为本task任务需要悬停,所以
            //位于该task栈空间上的node,不会被破坏,它和全局变量性质等同
                 OS_FlagBlock(pgrp, &node, flags, wait_type, timeout);
                 OS_EXIT_CRITICAL();
             }
             break;
#endif
        default:
             OS_EXIT_CRITICAL();
             flags_rdy = (OS_FLAGS)0;
             *perr = OS_ERR_FLAG_WAIT_TYPE;
             return (flags_rdy);
    }
//因为本task正在运行,所以本task现在的优先级最高,现在本task已经将自己从就绪控制矩阵--调度器(x,y)矩形阵列中
//把自己摘掉,所以调度函数OS_Sched()一定会切换到另一个task中执行新task的代码[gliethttp]
    OS_Sched();//具体参见《浅析μC/OS-II v2.85内核调度函数》
//2007-09-09 gliethttp
//可能因为OSFlagPend()中指定的timeout已经超时
//[由OSTimeTick()函数把本task重新置入了就绪控制矩阵,具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》],
//又或者确实在应用程序的调用了OSFlagPost(),最终使得flag事件组条件满足,
//以下代码将具体解析是有什么引起的:1.超时,2.收到正常信号
    OS_ENTER_CRITICAL();
    if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) {
//是因为timeout超时,使得本task获得重新执行的机会
        pend_stat = OSTCBCur->OSTCBStatPend;
        OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
//OS_FlagUnlink()把分配在本task栈空间上的局部变量node,从pgrp事件组双向链表上摘下来.
        OS_FlagUnlink(&node);
        OSTCBCur->OSTCBStat = OS_STAT_RDY;//本task正在运行,不悬停在任何事件控制矩阵上
        OS_EXIT_CRITICAL();
        flags_rdy = (OS_FLAGS)0;
        switch (pend_stat) {
            case OS_STAT_PEND_TO:
            default:
                 *perr = OS_ERR_TIMEOUT;//因为超时,本task才被调度
                 break;
            case OS_STAT_PEND_ABORT:
                 *perr = OS_ERR_PEND_ABORT;//人为取消
                 break;
        }
        return (flags_rdy);
    }
//由于每个事件都调用OSFlagPost()登记了事件自己,所以条件满足,本task被正常唤醒
//已经将本task在pgrp事件组双向链表上摘下来,并且把本task放入了就绪控制矩阵中,
//否则本task也不会执行至此.[gliethttp]
    flags_rdy = OSTCBCur->OSTCBFlagsRdy;
    if (consume == OS_TRUE) {
        switch (wait_type) {
            case OS_FLAG_WAIT_SET_ALL:
            case OS_FLAG_WAIT_SET_ANY:
            //清除flag事件组中的相应事件标志位
                 pgrp->OSFlagFlags &= ~flags_rdy;
                 break;
#if OS_FLAG_WAIT_CLR_EN > 0
            case OS_FLAG_WAIT_CLR_ALL:
            case OS_FLAG_WAIT_CLR_ANY:
            //还原flag事件组中的相应事件标志位
                 pgrp->OSFlagFlags |= flags_rdy;
                 break;
#endif
            default:
                 OS_EXIT_CRITICAL();
                 *perr = OS_ERR_FLAG_WAIT_TYPE;
                 return ((OS_FLAGS)0);
        }
    }
    OS_EXIT_CRITICAL();
    *perr = OS_ERR_NONE;
    return (flags_rdy);
}
//----------------------------------------------------------------------
//2.OS_FlagBlock()函数
static void OS_FlagBlock(OS_FLAG_GRP *pgrp, OS_FLAG_NODE *pnode, OS_FLAGS flags, INT8U wait_type, INT16U timeout)
{
    OS_FLAG_NODE *pnode_next;
    INT8U y;
//pnode指向本task在自己栈空间上分配的一个局部变量
//一个node描述一个task
    OSTCBCur->OSTCBStat |= OS_STAT_FLAG;//是Flag事件让本task进入悬停等待的
    OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;//假定不是超时,为正常收到信号
//超时,如果timeout=0,那么,本task将一直悬停,仅仅当收到事件触发信号后才重新进入调度队列
    OSTCBCur->OSTCBDly = timeout;
#if OS_TASK_DEL_EN > 0
    OSTCBCur->OSTCBFlagNode = pnode;
#endif
//一个node描述一个task
    pnode->OSFlagNodeFlags = flags;//该task对应的flag事件组值
    pnode->OSFlagNodeWaitType = wait_type;//该task对应的等待类型
    pnode->OSFlagNodeTCB = (void *)OSTCBCur;//该task的TCB任务上下文指针
    pnode->OSFlagNodeNext = pgrp->OSFlagWaitList;//把该node挂到pgrp->OSFlagWaitList头部
    pnode->OSFlagNodePrev = (void *)0;//因为是头部,所以没有prev
    pnode->OSFlagNodeFlagGrp = (void *)pgrp;//该task对应的pgrp管理组
    pnode_next = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;
    if (pnode_next != (void *)0) {
    //在本task之前,已经有其他task悬停在flag事件组上了
        pnode_next->OSFlagNodePrev = pnode;
    }
    pgrp->OSFlagWaitList = (void *)pnode;//设置本task为链表头部
    //把本task从就绪控制矩阵中摘下[gliethttp]
    y = OSTCBCur->OSTCBY;
    OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
    if (OSRdyTbl[y] == 0x00) {
    //当前y行对应的8个或16个task都已经悬停,那么当前y行也清除.
        OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
    }
}
//----------------------------------------------------------------------
//3.OS_FlagUnlink()函数
void OS_FlagUnlink (OS_FLAG_NODE *pnode)
{
#if OS_TASK_DEL_EN > 0
    OS_TCB *ptcb;
#endif
    OS_FLAG_GRP *pgrp;
    OS_FLAG_NODE *pnode_prev;
    OS_FLAG_NODE *pnode_next;
//把管理本task的node从pgrp双向链表中摘下来
    pnode_prev = (OS_FLAG_NODE *)pnode->OSFlagNodePrev;
    pnode_next = (OS_FLAG_NODE *)pnode->OSFlagNodeNext;
    if (pnode_prev == (OS_FLAG_NODE *)0) {
    //说明本node为双向链表头
        pgrp = (OS_FLAG_GRP *)pnode->OSFlagNodeFlagGrp;
        pgrp->OSFlagWaitList = (void *)pnode_next;//设置本task的下一个task作为链表头
        if (pnode_next != (OS_FLAG_NODE *)0) {
        //如果下一个task存在,那么将下一个task的node的prev设置成0,
        //进而来表征下一个task是链表头
            pnode_next->OSFlagNodePrev = (OS_FLAG_NODE *)0;
        }
    } else {
    //说明本node为双向链表中普通一员
        pnode_prev->OSFlagNodeNext = pnode_next;//直接跳过本node的链接
        if (pnode_next != (OS_FLAG_NODE *)0) {
    //下一个task存在,那么完成双向链表的prev项
            pnode_next->OSFlagNodePrev = pnode_prev;
        }
    }
#if OS_TASK_DEL_EN > 0
    ptcb = (OS_TCB *)pnode->OSFlagNodeTCB;
    ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0;
#endif
}
//----------------------------------------------------------------------
//4.OSFlagPost()函数
OS_FLAGS OSFlagPost(OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U opt, INT8U *perr)
{
    OS_FLAG_NODE *pnode;
    BOOLEAN sched;
    OS_FLAGS flags_cur;
    OS_FLAGS flags_rdy;
    BOOLEAN rdy;
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR cpu_sr = 0;
#endif

#if OS_ARG_CHK_EN > 0
    if (perr == (INT8U *)0) {
        return ((OS_FLAGS)0);
    }
    if (pgrp == (OS_FLAG_GRP *)0) {
        *perr = OS_ERR_FLAG_INVALID_PGRP;
        return ((OS_FLAGS)0);
    }
#endif
    if (pgrp->OSFlagType != OS_EVENT_TYPE_FLAG) {
        *perr = OS_ERR_EVENT_TYPE;
        return ((OS_FLAGS)0);
    }

    OS_ENTER_CRITICAL();
    //对flag事件组,进行位操作
    switch (opt) {
        case OS_FLAG_CLR:
             pgrp->OSFlagFlags &= ~flags;//清除flag标志组pgrp->OSFlagFlags中flags位为1的位
             break;
        case OS_FLAG_SET:
             pgrp->OSFlagFlags |= flags;//置位flag标志组pgrp->OSFlagFlags中flags位为1的位
             break;
        default://没有该操作,直接error返回
             OS_EXIT_CRITICAL();
             *perr = OS_ERR_FLAG_INVALID_OPT;
             return ((OS_FLAGS)0);
    }
    sched = OS_FALSE;
    pnode = (OS_FLAG_NODE *)pgrp->OSFlagWaitList;
//2007-09-10 gliethttp
//遍历悬停在pgrp->OSFlagWaitList双向链表上的所有task,唤醒满足flag事件组条件者
    while (pnode != (OS_FLAG_NODE *)0) {//双向链表中还有task没有运算
        switch (pnode->OSFlagNodeWaitType) {
//该node管理的task的等待类型
            case OS_FLAG_WAIT_SET_ALL:
                //flag事件组中所有事件都置位才唤醒
                 flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & pnode->OSFlagNodeFlags);
                 if (flags_rdy == pnode->OSFlagNodeFlags) {
                //flag事件组中指定的所有事件都已经登记了,那么将本task的node从flag事件组pgrp双向链表中
                //摘下来,如果本task仅仅在等待flag事件组的发生,那么将本task添加到就绪控制矩阵中,
                //等待os的调度
                     rdy = OS_FlagTaskRdy(pnode, flags_rdy);
                     if (rdy == OS_TRUE) {
                         sched = OS_TRUE;//本task被添加到了就绪控制矩阵中,为了rtos要求,需要调度
                     }
                 }
                 break;
            case OS_FLAG_WAIT_SET_ANY:
                //flag事件组中指定的事件们,只要有一个事件发生置位就唤醒
                 flags_rdy = (OS_FLAGS)(pgrp->OSFlagFlags & pnode->OSFlagNodeFlags);
                 if (flags_rdy != (OS_FLAGS)0) {
                //flag事件组中指定的所有事件都已经登记了,那么将本task的node从flag事件组pgrp双向链表中
                //摘下来,如果本task仅仅在等待flag事件组的发生,那么将本task添加到就绪控制矩阵中,
                //等待os的调度
                     rdy = OS_FlagTaskRdy(pnode, flags_rdy);
                     if (rdy == OS_TRUE) {
                         sched = OS_TRUE;//本task被添加到了就绪控制矩阵中,为了rtos要求,需要调度
                     }
                 }
                 break;
#if OS_FLAG_WAIT_CLR_EN > 0
            case OS_FLAG_WAIT_CLR_ALL:
                //flag事件组中所有事件都清0才唤醒
                 flags_rdy = (OS_FLAGS)(~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags);
                 if (flags_rdy == pnode->OSFlagNodeFlags) {
                //flag事件组中指定的所有事件都已经登记了,那么将本task的node从flag事件组pgrp双向链表中
                //摘下来,如果本task仅仅在等待flag事件组的发生,那么将本task添加到就绪控制矩阵中,
                //等待os的调度
                     rdy = OS_FlagTaskRdy(pnode, flags_rdy);
                     if (rdy == OS_TRUE) {
                         sched = OS_TRUE;//本task被添加到了就绪控制矩阵中,为了rtos要求,需要调度
                     }
                 }
                 break;
            case OS_FLAG_WAIT_CLR_ANY:
                //flag事件组中指定的事件们,只要有一个事件发生清0就唤醒
                 flags_rdy = (OS_FLAGS)(~pgrp->OSFlagFlags & pnode->OSFlagNodeFlags);
                 if (flags_rdy != (OS_FLAGS)0) {
                //flag事件组中指定的所有事件都已经登记了,那么将本task的node从flag事件组pgrp双向链表中
                //摘下来,如果本task仅仅在等待flag事件组的发生,那么将本task添加到就绪控制矩阵中,
                //等待os的调度
                     rdy = OS_FlagTaskRdy(pnode, flags_rdy);
                     if (rdy == OS_TRUE) {
                         sched = OS_TRUE;//本task被添加到了就绪控制矩阵中,为了rtos要求,需要调度
                     }
                 }
                 break;
#endif
            default:
                 OS_EXIT_CRITICAL();
                 *perr = OS_ERR_FLAG_WAIT_TYPE;
                 return ((OS_FLAGS)0);
        }
        pnode = (OS_FLAG_NODE *)pnode->OSFlagNodeNext;//下一个悬停在该flag事件组上的task
    }
    OS_EXIT_CRITICAL();
    if (sched == OS_TRUE) {
    //可能刚刚放到就绪控制矩阵上的被唤醒的task-A的优先级比调用OSFlagPost()函数的进程B优先级高
    //所以需要调用shedule函数,
    //如果真的高,那么调用OSFlagPost()函数的进程B就要被抢占,os将会切换到新的task去执行[gliethttp]
    //如果没有调用OSFlagPost()函数的进程B优先级高,那么os不会切换,仍然继续执行进程B,OSFlagPost()正常返回
        OS_Sched();
    }
    OS_ENTER_CRITICAL();
//返回当前的OSFlagFlags数值,如果因为OS_Sched()调度去执行了A进程,那么这里的OSFlagFlags
//数值可能已经被A进程的consume属性复了位.[gliethttp]
    flags_cur = pgrp->OSFlagFlags;
    OS_EXIT_CRITICAL();
    *perr = OS_ERR_NONE;
    return (flags_cur);
}
//----------------------------------------------------------------------
//5.OS_FlagTaskRdy()函数
static BOOLEAN OS_FlagTaskRdy (OS_FLAG_NODE *pnode, OS_FLAGS flags_rdy)
{
    OS_TCB *ptcb;
    BOOLEAN sched;

    ptcb = (OS_TCB *)pnode->OSFlagNodeTCB;
    ptcb->OSTCBDly = 0;//复原为正常
    ptcb->OSTCBFlagsRdy = flags_rdy;
//本task悬停的flag事件组已经发生,清除task上下文控制块上的OS_STAT_FLAG位
    ptcb->OSTCBStat &= ~(INT8U)OS_STAT_FLAG;
    ptcb->OSTCBStatPend = OS_STAT_PEND_OK;//正常收到信号
    if (ptcb->OSTCBStat == OS_STAT_RDY) {
//如果当前task只是等待该flag事件组,那么把该task放到就绪控制矩阵中,允许内核调度本task
        OSRdyGrp |= ptcb->OSTCBBitY;
        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
        sched = OS_TRUE;
    } else {
        sched = OS_FALSE;
    }
//OS_FlagUnlink()把分配在本task栈空间上的局部变量node,从pgrp事件组双向链表上摘下来,
//进而清除pgrp事件组中无本task的相关链接
    OS_FlagUnlink(pnode);
    return (sched);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
PS:"所以从这里来看,os中的各个功能单元管理着自己的事情,就像面向对象的封装一样,"
   "事件控制矩阵和就绪控制矩阵是各个对象独立自治的关键因素"
   "其他对象,都努力说服自己相信别的对象是独立的、可信任的、安全的"[gliethttp]
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

阅读(8486) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~