• 关于tsk和mbx


    这两个都是DSP/BIOS中的,先大概介绍一下

    tsk:
        task,任务.在Scheduling中,其优先级高于IDL(背景程序),低于SWI(软中断)和HWI(硬中断).可以被软硬中断打断,也可以被其它事件阻塞(blocked),顺便说一下,SWI和HWI是不能阻塞的.(阻塞和中断的不同,见我的另外一篇文章:CCS的一些问题)

    tsk和swi和hwi类似,可以调用一个函数,还可以传递多达8个参数,不同的tsk可以有15个优先级,执行任务的顺序相当于一个优先队列,如果一个tsk被阻塞,会自动将这个tsk放到同优先级tsk的后面,等待条件满足的时候执行.

    tsk有个重要的函数TSK_yield,当一个tsk调用这个函数的时候,会将自己挂起(pend),将控制权交给接下来的一个tsk,让他执行.

    查看不同的tsk的状态,可以选择"DSP/BIOS -> Kernel/Object View ",在出现的窗口左边点击tsk,就可以在右边看到所有tsk的状态(ready:准备好,running:运行中,blocked:被阻塞,terminal:结束)

    ------------------------------------------------------------------------------

    mbx:
        mailbox,邮箱.在Synchronization中.一般作为不同的任务(tsk)之间传递数据.

    mbx有两个属性,
    Size:这里面可以存放的单个数据的大小,比如想在这里面存放int类型的数值,那么Size就设为4.
    Length:里面最多能存放多少个大小为Size的数据,如果设为2,那么就能存放2个.

    主要函数:

    MBX_pend:

    语法:
    status = MBX_pend(mbx, msg, timeout);

    参数:
    MBX_Handle mbx; /* 句柄*/ 
    Ptr msg; /* 用以保存读取出来的数据的地址*/ 
    Uns timeout; /* 超时时间*/

    返回值:
    Bool status; /* 如果成功,返回TRUE if successful,如果timeout设定的时间内没有读取到数据,则返回 FALSE*/

    描述:

        如果mbx不为空,将复制其中的第一个数据到msg指定的地址并且返回TRUE.如果为空,这个任务将被挂起,直到MBX_post函数被调用或者timeout设置的时间到.
        如果timeout的值是SYS_FOREVER,那这个任务将一直挂起,直到MBX_post函数被调用,如果timeout的值是0,那么将立即返回FALSE.

    MBX_post:

    语法:
    status = MBX_post(mbx, msg, timeout);

    参数:
    MBX_Handle mbx; /* 句柄*/ 
    Ptr msg; /* 存放写入数据的地址*/ 
    Uns timeout; /*等待时间,如果超过此时间仍然不能写入,返回FALSE*/

    返回值:
    Bool status; /* 成功写入返回TRUE,超时返回FALSE */

    描述:
        MBX_post 检查mbx中是否有空闲的位置,如果有,则将msg的内容写入mbx.同时将下一个MBX_post任务(如果有的话)设为ready状态.
        如果mbx已经满了,而且timeout等于SYS_FOREVER,这个任务将被挂起,等待MBX_pend函数被调用.如果timeout等于0,那么立即返回FALSE.如果timeout是不为0的数,这个任务将等待这么长的时间,如果还是没有MBX_pend函数被调用,则返回FALSE.

    A task switch occurs when calling MBX_post if a higher priority task is made ready to run, or if there are no free message slots and timeout is not 0.

    这两个东西还有不少可以测试的地方,比如tsk的优先队列是怎么排的,调用TSK_yield后排到什么地方,mbx未放满是不是能读取,未读完是不是能放入,pend和post的Timeout值有什么用,这些等下次有空研究的时候补充.

    ===================================================

    在调试TI的一个例程tsktest(位置:X:\CCStudio_v3.1\tutorial\sim64xx\tsktest,其中的sim64xx根据你使用的DSP类型而定)的时候,花了不少时间,才终于理解了这里面任务调度的顺序.

    程序中有一个mbx,能放2个8B的数据,有4个tsk,1个是读mbx,3个写mbx,这三个写mbx的tsk调用的是同一个函数,不过为了区分,调用的时候传递了一个不同的参数.程序运行的结果这里就不写了.

    我经过改变mbx的length和write函数的循环写入次数后,可以确定mbx有自己的一个任务队列,当mbx满的时候,post过来的tsk会被blocked,但是这个post的动作已经是放在mbx的任务队列中,等到mbx被读空的时候,会自动开始这个post动作.如果在这个post动作后面还排着其它的动作,那么会接着执行后面的动作.

    举个现实中的例子,假设有ABC三队人在排队买票,每队3人,分别叫A1A2A3B1B2B3C1C2C3.他们在售票大厅外面的广场排队,售票大厅有一个门,要进大厅的人,必须在门前排成一队,然后才能进去.从各自的队伍排到门口的队伍,按照ABC的顺序,门口的队伍每队只能有一人.大厅里面有2个窗口在卖票,如果两个窗口都有人在买,那么后面的人只能排在门口,不能进大厅.只有当在两个窗口买票的人都离开后,排在后面的前两个人才能进大厅.进入大厅的人,如果自己的队伍还有人,必须通知下一个人过来排队.

    那么看一下买票和排队的顺序.

    一开始A1A2到门口,大厅空,
    两人进去,通知A3过来排队
    A3到门口,里面满了,在门口排队,
    A队已经一人在门外,就轮到B队了
    B1到门口排队,排在A3后面,B组结束,
    轮到C队,C1排到B1后面,C队结束.

    现在开始第一轮卖票,
    A1A2买完走人,大门可以进人,
    A3进大厅,因为A队没人了,不用通知,
    接着B1进入大厅,顺便通知B队的B2过来排队,B2只能排在C1后面.
    大厅又满,禁止进人,

    开始卖票,
    A3B1买完走人.大门开,
    C1进门,通知C2过来排队,C2排在B2后面,
    B2进门,通知B3来排队,B3排在C2后边.
    大厅满,

    开始卖票,
    C1B2买完走人.大厅空,门开,
    C2进,通知C3,C3排在B3后边,
    B3进大厅,B队没人,不用通知,
    大厅满,

    开始卖票,
    C2B3买完走人,大厅空,门开
    ,C3进,后边没人,不用通知,
    由于所有队都排完,大厅虽然没满,也开始卖票,
    C3买完走人.
    卖票的人等了一会,发现没人来买了,就关门回家了.

    买票的顺序就是A1A2 A3B1 C1B2 C2B3 C3

    再和tsk和mbx类比,三个tsk就是ABC三条队伍,每次要post一个数据,就是来门口排队,而门口的队伍就是mbx的任务队列,只有mbx中的内容被读完,才会依次启动任务队列中的任务

    1、它们都是任务间通信的手段,但是应用场合不同 
    信号量用作任务同步或者资源的互斥访问 
    至于邮箱,名副其实的,可以“邮寄”一些东东给别的任务 
    举个例子的话,我觉得可以说信号量就像别人打你电话只响一下(具体代表什么含义在于你们之间的约定),而邮箱就像短信哇,写啥都行。当然,二进制信号量也可以用邮箱实现。 
    2、任务与事件的概念不同 
    任务作为一个竞争系统资源的单位,各个待执行的任务被系统统一调度; 
    而任务之间(或者任务与中断之间)的互动体现在信号上,也就是事件。某些事件的发生可以使任务的运行状态发生变化。 
    比如两个任务A、B同时竞争某个资源,以信号量为途径实现互斥。 
    在A获得了信号量后,在使用资源的时候,B由于等待信号量而处于阻塞状态。 
    A使用完毕资源后,告知B“我用完了,你们用吧”,这个事件的传达是通过信号量完成的。 
    3、这个问题懒得敲了,复制粘贴之 
    “对信号量的初始计数值赋值。该初始值为0到65,535之间的一个数。如果信号量是用来表示一个或者多个事件的发生,那么该信号量的初始值应设为0。如果信号量是用于对共享资源的访问,那么该信号量的初始值应设为1(例如,把它当作二值信号量使用)。最后,如果该信号量是用来表示允许任务访问n个相同的资源,那么该初始值显然应该是n,并把该信号量作为一个可计数的信号量使用。” 

    可以一个任务对应多个事件吧,看你怎么设计了,比较简单的情况的话,一个任务可能也就关注一个事件。 
    关于初始值的问题,你说的应该是信号量的初始值吧,信号量最大的作用就是共享和竞争资源 
    初始值为n的情况,比如有n台打印机,每个时间点上一台打印机只有一个任务可以访问,如果有m个任务都想使用打印机,而且m>n的话,就有资源的征用问题,引入一个初始值为n的信号量,此信号量的数值所代表的就是“当前还有多少打印机可以使用”。想用打印机的任务去看信号量,如果还有的话就Take之,否则就等待(阻塞)或者先干别的去(不等待立即返回),同样的,使用过打印机的就Give之,以便其他任务可以使用打印机。 
    初值为0的情况也是普遍存在的,例如一个数据处理系统,任务A产生数据,缓存到一定数目后交给任务B做处理,这个事件使用信号量做通知的手段。那么系统初始化时,对B而言,是没有数据要处理的,那么信号量自然为0了。每当任务A提交一次数据,对信号量加1(做SemGive),任务B发现信号量非0后,就去处理数据,处理一个,对信号量减1(做SemTake)

    DSP/BIOS内核的应用程序中,优先级从低到高有四个线程:
    后台线程(IDL)线程;
    TSK(任务)线程;
    SWI线程(软件中断);
    HWI线程(硬件中断);
    应用程序从默认进入点_c_int00开始运行,首先完成系统的初始化,包括DSP/BIOS配置中指定的各个寄存器的设置以及PLL倍频时钟的设置等,然后调用main()函数,在main()函数结束返回,调用BIOS_start(),开始按优先级检测并执行HWI,SWI,TSK,当前面所有线程都没有执行时(没有HWI和SWI,有的任务已经完成,而有的被挂起),开始进入IDL_F_LOOP循环,执行后台的IDL线程(LOG模块的信息显示就是在IDL线程中完成的,CPU负荷图的数据也是这时读取并送到PC主机,以便完成图形绘制等)。在IDL_F_LOOP中,若有HWI,则立即暂停IDL,切换到硬件中断服务子程序。当硬件ISR完成后,根据具体情况判定有无SWI或唤醒任务,最后才回到IDL继续运行。
    注意,DSP/BIOS内核仍然是个多任务的内核,但并不是一个严格意义上的抢先式内核。除了HWI,其他所有线程都必须自己自动放弃对CPU的控制,以便完成切换。当然,当硬件中断发生后,也会产生线程的切换,这时所有线程都将按优先级重新安排运行,所以从这点讲,DSP/BIOS内核也具有抢先的特点。
    在DSP/BIOS内核应用中,用户可以将自己的处理代码(如G723的编码、解码,MP3 解压等)放到硬件中断,软件中断,任务或后台线程中的任何一个线程中调用运行。一般推荐在SWI和TSK中调用。用户可以在DSP/BIOS的配置文件中简单说明这些软件中断或任务(即所谓的静态说明),也可以在运行过程中通过DSP/BIOS内核提供的API函数调用动态创建。
    API函数调用几乎都可以使用C或C++语言直接调用。通过这些API,用户可以完成硬件中断的管理,软件中断的启动,任务的切换,各线程之间的同步和数据通信等。

  • 相关阅读:
    SVN错误:Attempted to lock an already-locked dir
    DecimalFormat 中的 # 与 0 的区别(中文帮助文档中翻译可能是错误的)
    Logger.getLogger和LogFactory.getLog的区别
    在做excel导出时如何将excel直接写在输出流中
    10 -- 深入使用Spring -- 5... 实现任务的自动调度
    8 -- 深入使用Spring -- 8...2 管理Hibernate的SessionFactory
    8 -- 深入使用Spring -- 8...1 Spring提供的DAO支持
    8 -- 深入使用Spring -- 8... Spring整合Hibernate
    8 -- 深入使用Spring -- 7...4 使用自动装配
    8 -- 深入使用Spring -- 7...3 让Spring管理控制器
  • 原文地址:https://www.cnblogs.com/fpga/p/1570051.html
Copyright © 2020-2023  润新知