上回书介绍了ping-pong机制,毫无疑问,ping-pong机制为了满足实时性的要求,本来是M的计算量的需求,几乎用了2M性能的计算单元来完成,具体为:ping在做M/2的工作,此时pong在实时handle message,ping处理完M/2的工作,发送中断给pong,pong就开始处理剩下M/2的工作,此时ping开始实时handle message。
综合以上,为了解决大约只有50%的利用率的问题,master-slave机制应运而生。即一个线程为master,负责触发任务,该任务由一个或多个slave线程来完成。一般的,在通信基站的基带,任务的触发,通常做成消息,或者时间来触发,所以,master线程主要负责handle message,收到一个消息,如果是简单的配置等轻量级处理,那么就直接在master线程处理,其他的,都由众多slave线程去处理。代码如下:
master_thread()
{
while(loop)
{
receive message;
case MSG1:
thing 1;
break;
case MSG2:
prepare ting2;
Trigger Thing2_thread;
Trigger Thing4_thread;
break;
case MSG3:
prepare thing 3;
trigger Thing3_thread;
break;
default:
something;
}
}
Thing2_thread(thread input)
{
do the thing;
}
Thing3_thread(thread input)
{
do the thing;
Trigger Thing5_thread;
}
Thing4_thread(thread input)
{
do the thing;
}
Thing5_thread(thread input)
{
do the thing;
}
软件架构大体如此,但是,对于计算单元而言,比如CPU,DSP,无论有多少个核,这些核的频率种类比较少,一般的都是一种,但对于little big架构里,可以有两种,或者三种,所以,一般的,如果性能只有一种,那么master和slave对于部署在一类核上,就没有什么讲究,但在写软件的时候,就要求尽量每个master或slave的各个线程计算量平均。如果处理单元的性能有两种,那么master的那个线程会部署在性能最好的核上,其他的slave线程运行在性能次之的核上,也是要求尽量按照处理单元的性能来设计每个salve。如果是三种或者三种以上,就要对slave做分类管理,以适配不同计算量的处理单元。上述代码例子,能较好的体现其灵活性。这里要求设计者要对业务相当懂,才能设计一个合适的方案。
老规矩,说完了计算,再说存储,由于每个master线程要一直运行,而slave线程大部分是单次运行,所以这种架构,对存储的设计提出来很高的要求。对于那些并行运行的slave线程,一定要注意锁的使用,如果软件业务布局设计的巧妙,可以避免用锁。对于串行运行的线程,一定要注意变量的作用域。关于内存的使用,我会在讲完分布式之后,单独用一篇文章来讲述。
简单介绍计算和存储之后,分析一下该架构的优劣。
优势之一就是计算单元的利用率很高。其二就是相较于ping-pong架构,由于core的频率降下来,那么每个核的功耗就降下来了。其三就是软件在迭代工程中,即使需要添加的feature有很大的计算量,但只要软件架构设计合理,比ping-pong的可拓展性要强很多。
当然,缺点就是开发难度加大。总的来说,多快好省,多了就不能快,好了就不能省,天经地义。